Skip to content
Monogem

Component · Core

Separator

Overview

A thin line that divides content into distinct groups — between sections of a card, items in a menu, or entries in a toolbar. Purely visual and structural: no click handler, no hover state, no keyboard focus.

Anatomy

A single line. No sub-parts — unlike Badge's icon-and-label or Checkbox's box-and-label, Separator has nothing to compose.

Live Example

Horizontal (decorative)

Sections of a card, stacked vertically.

A horizontal hairline divides them.

Vertical (decorative)

Docs
API
Support

Semantic (role="separator")

A thematic break in prose, exposed to assistive tech.

A screen reader announces this boundary.

Code Example

separator-showcase.tsx
import { Separator } from "@/components/ui/separator";

/**
* Live Separator example — a horizontal divider between stacked content and a
* vertical divider in a row (both decorative), plus one semantic separator
* (`decorative={false}` → `role="separator"`) for a real content boundary.
* Separator is static: no hover, no focus, no interaction.
*/
export function SeparatorShowcase() {
return (
<div className="flex flex-col gap-8">
<section className="flex flex-col gap-3">
<h3 className="text-sm font-medium leading-snug text-muted-foreground">
Horizontal (decorative)
</h3>
<div className="flex flex-col gap-4 text-sm leading-normal text-foreground">
<p>Sections of a card, stacked vertically.</p>
<Separator />
<p>A horizontal hairline divides them.</p>
</div>
</section>

<section className="flex flex-col gap-3">
<h3 className="text-sm font-medium leading-snug text-muted-foreground">
Vertical (decorative)
</h3>
<div className="flex h-8 items-center gap-4 text-sm leading-snug text-muted-foreground">
<span>Docs</span>
<Separator orientation="vertical" />
<span>API</span>
<Separator orientation="vertical" />
<span>Support</span>
</div>
</section>

<section className="flex flex-col gap-3">
<h3 className="text-sm font-medium leading-snug text-muted-foreground">
Semantic (role=&quot;separator&quot;)
</h3>
<div className="flex flex-col gap-4 text-sm leading-normal text-foreground">
<p>A thematic break in prose, exposed to assistive tech.</p>
<Separator decorative={false} />
<p>A screen reader announces this boundary.</p>
</div>
</section>
</div>
);
}

Variants

None. Orientation (above) is the only axis of variation — there's no color, style, or weight variant to choose between.

Orientation

Two orientations, chosen to match the layout it sits in:

OrientationSpansUse when
Horizontal (default)Full width of its container, --scale-px tallDividing stacked content — sections in a card, rows in a list
VerticalFull height of its container, --scale-px wideDividing side-by-side content — items in a horizontal toolbar or breadcrumb-like row

Orientation is a layout decision, not a visual one — the token and thickness don't change, only which dimension the line spans.

States

StateLook
Default--border line, --scale-px thick

Separator is static — nothing to hover, focus, activate, or disable.

Usage Guidance

Decorative vs. semantic

Most Separators in a UI are decorative: a visual grouping cue with no meaning a screen reader user needs announced, because the grouping is already conveyed by structure (headings, landmarks, list boundaries) or doesn't carry any real semantic weight. Default to decorative — a plain non-interactive element with no ARIA role, invisible to assistive tech, the same way a CSS border between two <div>s would be.

Mark a Separator semantic only when it's the sole signal of a meaningful boundary — most often a thematic break inside a block of prose content (e.g. a long-form article's scene break), rather than a UI layout divider. A semantic separator is exposed to assistive tech: role="separator", plus aria-orientation="vertical" when vertical (horizontal is the implicit ARIA default, so it needs no attribute). For a horizontal semantic break specifically, the native <hr> element is the simpler choice — it carries an implicit role="separator" on its own. <hr> has no vertical form, so a vertical semantic separator always needs the role/aria-orientation div pattern instead.

In short: reach for <hr> only inside real content flow; reach for the plain decorative div for everything else — which is most component and layout usage.

Separator vs. spacing, borders, and containers

Separator is one of three ways to create visual distance between things — reach for the one that matches the actual relationship:

NeedUse
Related items just need breathing room, no dividing lineSpacing alone (--scale-* gap) — see Spacing
A contained surface needs a defined edgeThe container's own --border (a card, an input) — not a Separator dropped along one side
Two groups need an explicit dividing line between them, distinct from ordinary spacingSeparator

A Separator is a signal, not a default. If padding and gap already read as separated groups, an added line is usually clutter, not clarity — reach for it when the line itself communicates something spacing alone doesn't.

Tokens

Separator uses existing Monogem semantic and primitive tokens to stay consistent with the design system. Both tokens already name this exact use case in Color: --border is documented for "Lines, dividers," and --scale-px is already the border-width recipe's "Default border — cards, inputs, sidebar, dividers."

TokenWhere used
--borderLine color
--scale-pxLine thickness (1px hairline)

Spacing around a Separator isn't a new token either — the gap on each side matches whatever --scale-* step already separates the sections it divides (see Spacing's task table), not a fixed value unique to Separator.

Do / Don’t

Do

  • Default to decorative — most Separators are layout dividers, not content boundaries.
  • Match orientation to the layout: horizontal in a vertical stack, vertical in a horizontal row.
  • Reuse the surrounding layout's existing spacing token on either side, rather than a one-off gap.

Don’t

  • Use a Separator as a substitute for a container's own border — a card's edge is --border on the card, not a Separator laid along one side.
  • Add a Separator where spacing alone already reads as separated groups.
  • Give Separator a click handler, hover state, or focus ring — it isn't interactive.
  • Stack multiple Separators, or pair one with heavy spacing on both sides — pick one.

Accessibility

  • Decorative (default): no ARIA role, not present in the accessibility tree, not announced — correct, since it carries no information beyond what's already structurally conveyed.
  • Semantic: role="separator" (or native <hr> for a horizontal content break), plus aria-orientation="vertical" when vertical.
  • Never the only way information is conveyed — a Separator (decorative or semantic) is a visual reinforcement of a grouping, not a substitute for real structure (headings, landmarks, list markup).
  • Not in the tab order either way — it's never interactive, regardless of decorative/semantic status.