Skip to content
All Taste components

Navigation

Segmented control

A small set of mutually exclusive options, such as a view switch or a date range.

text · icon and text · icon only · full width

"use client";
import { useState } from "react";
import { cn } from "@/lib/utils";

type Option<T extends string> = { value: T; label: string; icon?: React.ReactNode };

export function SegmentedControl<T extends string>({ options, defaultValue, onChange, label, block }:
  { options: Option<T>[]; defaultValue: T; onChange?: (v: T) => void; label: string; block?: boolean }) {
  const [value, setValue] = useState(defaultValue);
  return (
    <div role="group" aria-label={label} className={cn("max-w-full gap-0.5 rounded-lg bg-surface-2 p-0.5", block ? "flex w-full" : "inline-flex")}>
      {options.map((o) => (
        <button
          key={o.value}
          type="button"
          aria-pressed={value === o.value}
          aria-label={o.icon && !o.label ? o.value : undefined}
          onClick={() => { setValue(o.value); onChange?.(o.value); }}
          className={cn(
            "inline-flex h-7 items-center justify-center gap-1.5 whitespace-nowrap rounded px-3 text-[13px] font-medium text-fg-muted transition hover:text-fg [&_svg]:size-3.5",
            "aria-pressed:bg-bg aria-pressed:text-fg aria-pressed:shadow-sm",
            block && "min-w-0 flex-1",
          )}
        >
          {o.icon}
          {o.label}
        </button>
      ))}
    </div>
  );
}

// <SegmentedControl label="Date range" defaultValue="week"
//   options={[{ value: "day", label: "Day" }, { value: "week", label: "Week" }, { value: "month", label: "Month" }]} />

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.