component — navigation

Link Toggle Group

A segmented control rendered as anchor links inside a tablist, for view switches that are real navigations. Styled with the quebi design system.

  • navigation
  • tabs
  • toggle
  • segmented
  • links

03 examples

Default

Each segment is a link; the current value takes the selected tint.

Two options

Works for a simple binary view switch.

First selected

The active segment can be anywhere in the group.

source

link-toggle-group.tsx

Copy this into your project. Resolve its dependencies from the registryDependencies in the component's API entry.

"use client"

import type { ReactNode } from "react"
import { cn } from "@/lib/utils"

/**
 * LinkToggleGroup — quebi design system
 *
 * A segmented control rendered as a row of anchor links inside a tablist.
 * Use it for view switches that are real navigations (each option has an
 * href) — e.g. day/week/month, or list/board. The current segment is the
 * `selected` ground with a `signal` label, the same state as ToggleGroup.
 *
 * Self-contained: only `@/lib/utils` and React. No sibling component deps.
 */

export type LinkToggleGroupOption<T extends string = string> = {
  value: T
  label: ReactNode
  href: string
}

export interface LinkToggleGroupProps<T extends string = string> {
  options: LinkToggleGroupOption<T>[]
  current: T
  ariaLabel: string
  className?: string
}

export function LinkToggleGroup<T extends string = string>({
  options,
  current,
  ariaLabel,
  className,
}: LinkToggleGroupProps<T>) {
  return (
    <div
      role="tablist"
      aria-label={ariaLabel}
      className={cn(
        "inline-flex items-center gap-0.5 rounded-(--q-radius-control) border border-quebi-hairline p-0.5",
        className,
      )}
    >
      {options.map((opt) => {
        const isActive = current === opt.value
        return (
          // biome-ignore lint/correctness/noRestrictedElements: these anchors are the tabs of a tablist — role="tab" and aria-selected are the component's purpose, and react-aria's Link does not accept a role override.
          <a
            key={opt.value}
            role="tab"
            aria-selected={isActive}
            href={opt.href}
            className={cn(
              "rounded-(--q-radius-mark) px-3 py-1.5 text-sm font-medium",
              "outline-none transition-colors duration-150",
              "focus-visible:ring-2 focus-visible:ring-quebi-focus focus-visible:ring-offset-2 focus-visible:ring-offset-quebi-bg",
              isActive
                ? "bg-quebi-selected text-quebi-signal"
                : "text-quebi-fg-muted hover:bg-quebi-raised hover:text-quebi-fg",
            )}
          >
            {opt.label}
          </a>
        )
      })}
    </div>
  )
}