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.

Section A
Section B
Item 1Item 2Item 3

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-stylesolid (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=solid
variant=dashed
variant=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=sm
size=md
size=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=default
tone=muted
tone=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

ARAna Radu8 min readNew
<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

Props

PropTypeDefaultDescription
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.
labelReactNodeInline 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`.
decorativebooleanWhen 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.
…restHTMLAttributes<HTMLDivElement>Native div attributes are forwarded — `style`, `id`, `className`, etc.