Skip to the content

Capsid menu

components/segmented/segmented.react.tsx

42 lines and 3 functions in DrDustinEdwards/capsomer, at commit d3966cc on 2026-10-24. This file on GitHub.

Functions

The functions of segmented.react.tsx
FunctionLinesComplexityCoveredCRAPMutation
Segmented30 to 457No data: no coverage report in this mapNo data: no coverage report in this mapNo data: mutation testing has not run on this repo yet
<anonymous:37>37 to 413No data: no coverage report in this mapNo data: no coverage report in this mapNo data: mutation testing has not run on this repo yet
<anonymous:39>39 to 391No data: no coverage report in this mapNo data: no coverage report in this mapNo data: mutation testing has not run on this repo yet

Imports

It imports no other module of this repo. No module of this repo imports it.

Source

import { useId, type ReactNode } from "react";

export interface SegmentedOption<V extends string> {
  value: V;
  label: ReactNode;
  disabled?: boolean;
}

export interface SegmentedProps<V extends string> {
  // What is being chosen. Always given; hideLegend keeps it for screen readers only, where
  // the context already says it (a theme switch in the top bar).
  legend: ReactNode;
  hideLegend?: boolean;
  // Two to five.
  options: Array<SegmentedOption<V>>;
  value: V | null;
  onChange: (value: V) => void;
  // The radios' name, for a form; one is made up otherwise.
  name?: string;
  // The id of text that says why an option is disabled.
  describedBy?: string;
  size?: "sm" | "default" | "lg";
  orientation?: "horizontal" | "vertical";
  // Fill the row, the segments sharing it.
  fill?: boolean;
  // Wrong: marks the radios aria-invalid; say why in text that describedBy names.
  invalid?: boolean;
}

export function Segmented<V extends string>({ legend, hideLegend = false, options, value, onChange, name, describedBy, size = "default", orientation = "horizontal", fill = false, invalid = false }: SegmentedProps<V>) {
  const own = useId();
  if ((options.length < 2 || options.length > 5)) console.warn("Segmented: use it for two to five options; a select or a combobox for more.");
  return (
    <fieldset className="cap-seg" aria-describedby={describedBy}>
      <legend className={hideLegend ? "cap-sr-only" : undefined}>{legend}</legend>
      <div className="cap-seg-options" data-size={size === "default" ? undefined : size} data-orientation={orientation === "vertical" ? "vertical" : undefined} data-fill={fill ? "" : undefined}>
        {options.map((o) => (
          <label key={o.value}>
            <input type="radio" name={name ?? own} value={o.value} checked={value === o.value} disabled={o.disabled} aria-invalid={invalid || undefined} onChange={() => onChange(o.value)} /> {o.label}
          </label>
        ))}
      </div>
    </fieldset>
  );
}