Separator
Thin divider for stacking sections, breaking inline groups, or framing a labelled section header ("OR", "TODAY"). Three line styles, three thicknesses, three tones, built-in spacing presets, and an optional inline label that auto-flips the ARIA semantics so screen readers announce the section transition.
Usage
import { Separator } from '@bwo-ui/react';
<Separator />
<Separator orientation="vertical" />
<Separator label="Or continue with" />
<Separator variant="dashed" tone="muted" />Variants
Three line styles map straight to border-style — solid (default), dashed, dotted. Use solid for hard section breaks; dashed for "optional / cut here" semantics (settings sections, draft markers); dotted for the lightest possible separation when two regions are otherwise visually cohesive.
variant=solidvariant=dashedvariant=dotted<Separator variant="solid" />
<Separator variant="dashed" />
<Separator variant="dotted" />Sizes
sm (1 px, default), md (2 px), lg (4 px). Thicker separators read as bigger structural breaks — chapter dividers, between major sections in a long page, or framing a key callout.
size=smsize=mdsize=lg<Separator size="sm" /> {/* default */}
<Separator size="md" />
<Separator size="lg" />Tones
default uses the kit's standard border colour; muted steps the opacity down for a barely-there divider; strong jumps to the body text colour for editorial pull-quotes and high-emphasis breaks.
tone=defaulttone=mutedtone=strong<Separator tone="default" />
<Separator tone="muted" />
<Separator tone="strong" />Labelled
Pass a label and the separator renders as line / label / line. Use it for the "OR" between sign-in methods, "TODAY" / "YESTERDAY" chunkers in a feed, or year markers in a timeline. labelAlign shifts the label off-centre — start for left-aligned (typical for date markers), end for right-aligned (less common but useful for annotations).
When a label is set, the separator is no longer decorative — it auto-acquires role="separator" and the label becomes its accessible name. Override with decorative={true} if it's genuinely purely visual.
<Separator label="Or continue with" />
<Separator label="Today" labelAlign="start" />
<Separator label="2026" labelAlign="end" tone="muted" />
<Separator label="Dashed group" variant="dashed" size="md" />Spacing
spacing adds built-in margin around the separator so you don't have to wrap it. sm = 8 px, md = 16 px, lg = 24 px — applied to the top/bottom on horizontal separators and left/right on vertical ones.
Block above the separator.
Block below the separator. With spacing="lg" the gap is 24 px on each side, no wrapper margins required.
<Separator spacing="sm" />
<Separator spacing="md" />
<Separator spacing="lg" />Recipes
Auth form "OR" divider
The classic use case — separating social sign-in buttons from a magic-link / password form. label="Or" plus spacing="md" handles the layout in one node.
Sign in to Boogie
<Card>
<CardHeader><CardTitle>Sign in to Boogie</CardTitle></CardHeader>
<Button variant="outline">Continue with GitHub</Button>
<Button variant="outline">Continue with Google</Button>
<Separator label="Or" spacing="md" />
<input className="bwo-input" placeholder="you@boogie.ro" />
<Button variant="primary">Send magic link</Button>
</Card>Toolbar group dividers
Vertical separators chunk a horizontal toolbar into related action groups — text styling, links / code, embeds. Pair with spacing="sm" for the tight 8 px gutter that reads as "same control surface, different group".
<div role="toolbar" style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
<Button size="sm" variant="ghost">Bold</Button>
<Button size="sm" variant="ghost">Italic</Button>
<Separator orientation="vertical" style={{ height: 22 }} spacing="sm" />
<Button size="sm" variant="ghost">Link</Button>
<Button size="sm" variant="ghost">Code</Button>
<Separator orientation="vertical" style={{ height: 22 }} spacing="sm" />
<Button size="sm" variant="ghost">Image</Button>
<Button size="sm" variant="ghost">Embed</Button>
</div>Article meta row
Inline metadata rows (author · read time · status badge) use vertical separators between items. Give them an explicit height (~14 px) so they don't collapse to 0 inside small text.
How we ship motion on the web
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<Avatar fallback="AR" size="xs" />
<span>Ana Radu</span>
<Separator orientation="vertical" style={{ height: 14 }} />
<span>8 min read</span>
<Separator orientation="vertical" style={{ height: 14 }} />
<Badge size="sm" variant="green">New</Badge>
</div>Accessibility
- A plain Separator is purely decorative by default — it renders
aria-hiddenand screen readers skip it. That's correct for visual chunkers between unrelated regions. - When you pass
label, the separator becomes a real section marker:role="separator"with the label as the accessible name. Screen readers will announce "Or, separator". - Override with
decorative={false}on a plain Separator if it marks a meaningful structural break that screen readers should pause on (e.g. between two distinct article sections that don't have their own headings). - Conversely, set
decorative={true}on a labelled separator if the label is purely cosmetic (a decorative timeline year marker that's already part of the visible UI elsewhere). - Don't rely on a separator alone to convey hierarchy. If two regions are genuinely separate, they should also have headings, regions, or list roles — the separator is the visual cue on top of that semantic structure.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | 'horizontal' | 'vertical' | 'horizontal' | Axis of the line. Vertical separators need a height — either from a flex parent (`align-self: stretch`) or an inline `style={{ height: … }}`. |
variant | 'solid' | 'dashed' | 'dotted' | 'solid' | Line style. Maps to `border-style`. |
size | 'sm' | 'md' | 'lg' | 'sm' | 1 / 2 / 4 px thickness. |
tone | 'default' | 'muted' | 'strong' | 'default' | Colour weight — `muted` is barely there, `strong` jumps to the body-text colour. |
spacing | 'none' | 'sm' | 'md' | 'lg' | 'none' | Built-in margin (8 / 16 / 24 px) on the axis perpendicular to the line. Skips the need for a wrapper. |
label | ReactNode | — | Inline label that breaks the line on either side. Horizontal-only. Auto-flips ARIA to `role="separator"`. |
labelAlign | 'start' | 'center' | 'end' | 'center' | Where the label sits in the line. Only used with `label`. |
decorative | boolean | — | When true, the separator is hidden from assistive tech (`aria-hidden`). Defaults to true for plain separators and false for labelled ones — override either way as needed. |
…rest | HTMLAttributes<HTMLDivElement> | — | Native div attributes are forwarded — `style`, `id`, `className`, etc. |