Elements

List item

View in Figma

List leaf that renders either a navigation row or a controlled filter tag.

Install

npx shadcn@latest add @alix/listItem

Preview

Usage

<ListItem variant="text" text="Energy transition" href="/services/energy-transition" />
<ListItem
  variant="tag"
  text="Shipping"
  value="shipping"
  selected={selected.includes("shipping")}
  onSelect={toggle}
/>

Examples

01

Small navigation rows

Use the small text size for dense secondary navigation while preserving the full-row hit target.

<ul className="m-0 w-full max-w-sm list-none border-l border-border p-0 pl-2">
  <ListItem
    variant="text"
    text="Turnaround and restructuring"
    href="/services/turnaround"
    size="small"
    current
  />
  <ListItem
    variant="text"
    text="Transactions and investor services"
    href="/services/transactions"
    size="small"
  />
  <ListItem
    variant="text"
    text="Performance improvement"
    href="/services/performance"
    size="small"
  />
</ul>
02

Controlled filter tags

Tag items emit their stable value and let the parent own selection state.

Insight filters2 active
const [selected, setSelected] = useState(["restructuring", "transactions"]);
const toggle = (value: string) =>
  setSelected((current) =>
    current.includes(value)
      ? current.filter((item) => item !== value)
      : [...current, value],
  );

return (
  <div className="w-full max-w-md space-y-3">
    <div className="flex items-center justify-between gap-4">
      <span className="text-sm font-medium text-foreground">
        Insight filters
      </span>
      <Badge variant="primary">{selected.length} active</Badge>
    </div>
    <ul className="m-0 flex list-none flex-wrap gap-2 p-0">
      <ListItem
        variant="tag"
        text="Restructuring"
        value="restructuring"
        selected={selected.includes("restructuring")}
        onSelect={toggle}
      />
      <ListItem
        variant="tag"
        text="Performance"
        value="performance"
        selected={selected.includes("performance")}
        onSelect={toggle}
      />
      <ListItem
        variant="tag"
        text="Transactions"
        value="transactions"
        selected={selected.includes("transactions")}
        onSelect={toggle}
      />
    </ul>
  </div>
);
03

List parent recipe

Let List render repeated items from data when the row structure should stay uniform.

<div className="w-full max-w-sm">
  <List
    variant="list"
    title="Capabilities"
    size="small"
    items={[
      {
        text: "Turnaround and restructuring",
        href: "/services/turnaround",
        current: true,
      },
      {
        text: "Performance improvement",
        href: "/services/performance",
      },
      {
        text: "Investigations and disputes",
        href: "/services/investigations",
      },
    ]}
  />
</div>

When to use it

Use it for

  • Single navigation rows inside a locally owned `<ul>` when the parent needs exact control.
  • Controlled filter chips where the selected values live beside the result set.
  • Current-page state for section navigation that should set `aria-current`.

Reach for something else

  • CMS-fed lists of repeated rows — use List instead.
  • Static labels that do not toggle filtering — use Badge instead.
  • Command menus or overflow actions — use Menu instead.

Props

PropTypeDefaultDescription
variant"text" | "tag"Discriminates the item contract: text renders a navigation link; tag renders a filter button.
size"default" | "small""default"Text-item row height and padding; not valid on tag items.
currentbooleanfalseText-item current-page state, applied as aria-current.
selected / onSelectboolean / (value: string) => voidControlled tag state; ListItem emits its value and the parent owns selection.

See also