Reticle@etched/reticle 0.0.0

Radio

Pick one value from a few options. Arrow keys move between them. It is a field of its own; do not put it in a Field.

Kumo source
Retry policy
import { RadioGroup, RadioItem } from "@etched/reticle/radio";

export function Preview() {
  return (
    <RadioGroup legend="Retry policy" defaultValue="once">
      <RadioItem value="never" label="Never" />
      <RadioItem value="once" label="Once" />
      <RadioItem value="always" label="Until it passes" />
    </RadioGroup>
  );
}

Installation

import { RadioGroup, RadioItem, RadioLegend } from "@etched/reticle/radio";

Examples

Groups

Retry policy

Applies to runs that fail on a bench error.

Employment
Rows per page
Label first
Would you bet on them?
Choose an answer.
Region (locked)
Reviewer (optional)
import { useState } from "react";
import { RadioGroup, RadioItem } from "@etched/reticle/radio";

export function Groups() {
  const [size, setSize] = useState(25);

  return (
    <div className="grid">
      <RadioGroup legend="Retry policy" description="Applies to runs that fail on a bench error." defaultValue="once">
        <RadioItem value="never" label="Never" />
        <RadioItem value="once" label="Once" />
        <RadioItem value="always" label="Until it passes" />
        <RadioItem value="custom" label="Custom (admins only)" disabled />
      </RadioGroup>
      <RadioGroup legend="Employment" orientation="horizontal" name="employment">
        <RadioItem value="full-time" label="Full-time" />
        <RadioItem value="internship" label="Internship" />
      </RadioGroup>
      <RadioGroup<number> legend="Rows per page" orientation="horizontal" value={size} onValueChange={setSize}>
        {[10, 25, 50].map((n) => (
          <RadioItem<number> key={n} value={n} label={String(n)} />
        ))}
      </RadioGroup>
      <RadioGroup legend="Label first" controlPosition="end" defaultValue="a">
        <RadioItem value="a" label="Option A" />
        <RadioItem value="b" label="Option B" />
      </RadioGroup>
      <RadioGroup legend="Would you bet on them?" required error="Choose an answer.">
        <RadioItem value="yes" label="Yes" />
        <RadioItem value="no" label="No" />
        <RadioItem value="complicated" label="It’s complicated" />
      </RadioGroup>
      <RadioGroup legend="Region (locked)" disabled defaultValue="us">
        <RadioItem value="us" label="United States" />
        <RadioItem value="tw" label="Taiwan" />
      </RadioGroup>
      <RadioGroup legend="Reviewer" required={false}>
        <RadioItem value="me" label="Me" />
        <RadioItem value="team" label="Anyone on the team" />
      </RadioGroup>
    </div>
  );
}

Cards

The cards of a card group join into one card, with the circle at the end.

Plan
Domain strength
Bench (circle first)
Report format
Choose a format.
import { RadioGroup, RadioItem } from "@etched/reticle/radio";

const percentiles = [
  { value: "top-1", label: "Top 1%" },
  { value: "top-5", label: "Top 5%" },
  { value: "top-10", label: "Top 10%" },
  { value: "top-25", label: "Top 25%" },
  { value: "below", label: "Below top 25%" },
  { value: "unsure", label: "Not sure" },
];

export function Cards() {
  return (
    <div className="grid">
      <RadioGroup legend="Plan" appearance="card" defaultValue="standard">
        <RadioItem value="standard" label="Standard" description="Runs on shared benches, results in a day." />
        <RadioItem value="priority" label="Priority" description="Runs first on the next free bench." />
        <RadioItem value="dedicated" label="Dedicated" description="Needs a reserved bench." disabled />
      </RadioGroup>
      <RadioGroup legend="Domain strength" appearance="card" orientation="horizontal" defaultValue="top-5">
        {percentiles.map((p) => (
          <RadioItem key={p.value} value={p.value} label={p.label} />
        ))}
      </RadioGroup>
      <RadioGroup legend="Bench (circle first)" appearance="card" controlPosition="start" defaultValue="shared">
        <RadioItem value="shared" label="Shared" description="Any free bench in the lab." />
        <RadioItem value="reserved" label="Reserved" description="The bench booked for this run." />
      </RadioGroup>
      <RadioGroup legend="Report format" appearance="card" required error="Choose a format.">
        <RadioItem value="summary" label="Summary" description="One page per run." />
        <RadioItem value="full" label="Full" description="Every log line and chart." />
      </RadioGroup>
    </div>
  );
}

Segmented

Window
Window (disabled)
import { RadioGroup, RadioItem } from "@etched/reticle/radio";

export function Segmented() {
  return (
    <div className="grid">
      <RadioGroup legend="Window" appearance="segmented" defaultValue="12h">
        <RadioItem value="1h" label="1h" />
        <RadioItem value="12h" label="12h" />
        <RadioItem value="24h" label="24h" />
        <RadioItem value="7d" label="7d" disabled />
      </RadioGroup>
      <RadioGroup legend="Window (disabled)" appearance="segmented" defaultValue="1h" disabled>
        <RadioItem value="1h" label="1h" />
        <RadioItem value="12h" label="12h" />
      </RadioGroup>
    </div>
  );
}

A description that follows the value

The meaning of the chosen score shows under the group, and screen readers read it with the group. It works on touch, where a tooltip would not.

Conviction

Additional backchannel or tribal knowledge about this person

import { useState } from "react";
import { RadioGroup, RadioItem } from "@etched/reticle/radio";

const meanings = new Map([
  ["1", "Profile looks good, unsure"],
  ["2", "Profile looks extra good, unsure"],
  ["3", "Additional backchannel or tribal knowledge about this person"],
  ["4", "Certified superstar has been deeply referenced"],
]);

export function ADescriptionThatFollowsTheValue() {
  const [score, setScore] = useState("3");

  return (
    <RadioGroup legend="Conviction" appearance="segmented" value={score} onValueChange={(value) => setScore(String(value))} description={meanings.get(score)}>
      {[...meanings.keys()].map((value) => (
        <RadioItem key={value} value={value} label={value} />
      ))}
    </RadioGroup>
  );
}

API reference

RadioGroup

PropTypeDefaultDescription
legendReactNode–Title of the group. Without it, add a RadioLegend child or an aria-label.
children *ReactNode–RadioItem children, and optionally a RadioLegend.
orientation"vertical" | "horizontal""vertical"
appearance"default" | "card" | "segmented""default"Card items join into one card.
descriptionReactNode–Help text below the group. Hidden while an error shows.
errorFieldError–Error below the group. It marks every radio invalid.
controlPosition"start" | "end""start", or "end" for cards
requiredboolean–false adds the optional marker after the legend. true makes a choice required in a form.
classNamestring–Class on the outer element, for layout.

RadioItem

PropTypeDefaultDescription
variant"default" | "error""default"
appearanceRadioItemAppearance–Overrides the group's default or card appearance. A segmented group ignores it.
label *ReactNode–
descriptionReactNode–Secondary text under the label. It describes the option; it is not part of its name. Not shown when segmented.
value *T–
classNamestring–Class on the outer element, for layout.

RadioLegend

PropTypeDefaultDescription
children *ReactNode–
classNamestring–