Separator

A hairline rule for separating sibling content — the visual analogue of <hr>. Horizontal by default, vertical when stretched between flex / grid children. Decorative by default so it stays out of the accessibility tree; flip decorative={false} to announce a semantic break with role="separator" and the matching aria-orientation.

The journeyThree ways to see what you built
Step 1
Step 2
Step 3

Last block is a semantic separator (role="separator").

Installation

npx shadcn@latest add https://craftbits.dev/r/separator.json

Usage

import { Separator } from "@craft-bits/core";
 
<Separator />

Stretch a vertical rule between inline siblings inside a flex row:

<div className="flex h-5 items-center gap-4">
  <span>Step 1</span>
  <Separator orientation="vertical" />
  <span>Step 2</span>
</div>

Announce the break to assistive tech when the rule separates groups of content:

<Separator decorative={false} />

Understanding the component

  1. Hairline rule, not a heading. Separator renders a 1px filled <div> painted with --cb-border-muted. Pair it with a heading underneath when you need an a11y landmark; keep it on its own when the break is purely visual.
  2. Orientation drives sizing. horizontal (default) sets h-px w-full so the rule fills the row. vertical sets h-full w-px self-stretch so the rule grows to its flex / grid track height — pin a height on the parent for the rule to land.
  3. Decorative is the safe default. decorative renders role="none" and skips aria-orientation, matching <hr aria-hidden>. decorative={false} exposes role="separator" plus aria-orientation="vertical" when the orientation is vertical; horizontal is the WAI-ARIA implicit default so the attribute is omitted.
  4. Data hooks. The root carries data-cb-separator, data-orientation, and data-decorative so consumers can target nested regions without re-deriving props.
  5. No motion. The component is fully static — reduced-motion respect is the responsibility of the surrounding layout.

Variants

Horizontal (default)

<Separator />

Vertical

<div className="flex h-5 items-center gap-4">
  <span>Step 1</span>
  <Separator orientation="vertical" />
  <span>Step 2</span>
</div>

Announced (non-decorative)

<Separator decorative={false} />

Props

PropTypeDefaultDescription
orientation'horizontal' | 'vertical''horizontal'Layout axis. horizontal sets h-px w-full; vertical sets h-full w-px self-stretch.
decorativebooleantrueWhen true, renders role="none" and omits aria-orientation. When false, renders role="separator" and exposes aria-orientation on the vertical variant.
classNamestringMerged onto the rendered <div> via cn().
...restHTMLAttributes<HTMLDivElement>Any other <div> attribute.

Accessibility

  • Decorative separators render role="none" and are never announced to assistive tech — the WAI-ARIA pattern for purely-visual breaks.
  • Non-decorative separators render role="separator". The horizontal orientation matches the ARIA default, so aria-orientation is omitted; the vertical orientation explicitly sets aria-orientation="vertical".
  • Colour contrast: the rule paints with --cb-border-muted, which clears the WCAG 3:1 UI-component contrast threshold on the default --cb-bg and --cb-bg-elevated surfaces.
  • No motion. Reduced-motion respect is the responsibility of the surrounding content.

Credits

  • Extracted from: algoflashcards (src/platform/ui/separator.tsx). The original wrapped radix-ui's Separator.Root to inherit the same ARIA semantics. craft-bits drops the Radix dependency in favour of a direct DOM render — the role / orientation logic is small enough that the runtime cost outweighs the peer-dep cost — and swaps the raw bg-border Tailwind class for the cb-token-driven bg-cb-border-muted.