Skip to content

Separator

A line that divides content, and — unless you opt out — tells a screen reader that it does. It runs either way: horizontal across stacked content, vertical down a row. Give it children and it splits around them, a label set into the line.

separator/horizontal.tsx

Billing

Visa ending 4242 · renews 1 September

Notifications

Email only · digest at 09:00

Import

import { Separator } from "@forte-ui/react";

Examples

Vertical

Set orientation="vertical" and the rule turns, along with the aria-orientation it reports.

A vertical separator is an empty box, so it has no length of its own. Inside a flex row it stretches to the tallest sibling; anywhere else — in ordinary flow, or between inline items like the metadata below — it falls back to one line's height. That floor is --forte-separator-min-length, and it is the only reason a vertical rule is ever visible outside a flex container.

separator/vertical.tsx
DraftEdited 3 minutes ago2 collaborators

In a toolbar the stretch is the point: the rule matches whatever it sits between, without anyone measuring the buttons.

separator/toolbar.tsx

Line style

variant is the whole visual API — a rule has exactly one dimension. solid reads as a structural division; dashed and dotted read as provisional ones, which is what you want for a drop zone's edge or an optional section.

separator/variants.tsx
solid
dashed
dotted

With a label

Put children on the rule and the line splits around them — one half either side, the label between. or between two ways in is the canonical case:

separator/labeled.tsx

It works vertically too. The label stays upright, with a half-line above and below it, and in a flex row the halves stretch to the taller sibling exactly as the plain rule does:

separator/labeled-vertical.tsx

Upload a file

CSV or JSON, up to 10 MB.

Paste a link

One difference from the plain rule: a labeled vertical one has no length floor. Outside a flex or grid row its halves have nothing to be, and only the label shows. That is deliberate — the floor the halves would need is two line boxes plus the label, and a flex row is sized from its items, so a toolbar-height row holding one would grow to fit it. Give it a row.

Text is the usual label, but anything renders — an icon, a Badge, a Kbd. The label is deliberately no louder than the rule it sits on: small, muted and medium weight, from --forte-separator-label-font-size, --forte-separator-label-color and --forte-separator-label-font-weight, with --forte-separator-label-gap between it and the line. A label on a divider is secondary text by definition; if yours needs to be a heading, it is a heading, and the rule should sit under it instead.

A labeled rule is named by its label — see Accessibility.

Spacing and inset

Two knobs place the rule, and they are named after the axes rather than after margin because which physical side each one touches flips with the orientation:

  • --forte-separator-spacing runs along the axis being separated — the gap between the rule and the content on either side of it.
  • --forte-separator-inset runs across it — how far the rule is pulled in from the container's edges. Negative values push it back out, which is how a rule inside a padded panel becomes full-bleed.

Both default to 0, because the common case is a flex or grid parent whose gap already does the spacing and a built-in margin would double it.

separator/custom.tsx
Overview
Members
Integrations
Danger zone

In prose

Separator renders a <div>. Where the division is a genuine thematic break in running text, swap the element for the one HTML already has:

<Separator render={<hr />} />

The styles follow. The UA gives <hr> an inset 3D border and a 0.5em auto margin; both are cleared before this component paints its own single edge, so an <hr> and a <div> separator are pixel-identical.

Not with a label, though: <hr> is a void element and cannot hold one.

Accessibility

Base UI renders role="separator" with an aria-orientation matching the prop, so the division is announced rather than merely drawn.

That is right when the rule is the grouping. It is noise when the grouping is already carried by a heading, a landmark or a list and the rule only reinforces it visually — a screen reader then reads the page's decoration out loud. Pass decorative for that case:

<Separator decorative />

Labels

A labeled rule is named by its label: the root carries aria-labelledby pointing at it, so a screen reader announces "or, separator" rather than passing over the line. The attribute is doing real work: separator is a role whose children are presentational, so text left loose inside one is not guaranteed to be exposed at all. Your own aria-label or aria-labelledby wins if you pass one.

decorative still drops the role, and only the role. There is no name to give a role="none" element, so the label simply stays in the tree as plain text — right for a date between two runs of messages, which a screen reader should still hear. Where the label is visual rhetoric and nothing more — or between two buttons that already say what they do — hide the whole thing:

<Separator decorative aria-hidden>or</Separator>

Theming

The line is painted with a border, never background-color. Under forced-colors a background is replaced with a system color — for a plain box that is Canvas, the page's own backdrop — so a hairline drawn that way disappears for exactly the users who most need the grouping cue. Border colors are forced to CanvasText instead, so the rule survives with no forced-colors rule in the stylesheet at all.

Nothing here transitions. A separator has no states, so there is nothing to animate, and a color transition would only make it lag behind the rest of the page on a theme switch.

Theming tokens for Separator
PropertyControlsDefault
--forte-separator-colorLine colorvar(--forte-color-border-muted)
--forte-separator-thicknessLine thickness1px
--forte-separator-styleLine style; variant sets thissolid
--forte-separator-spacingMargin along the axis being separated0px
--forte-separator-insetMargin across it — how far in from the edges0px
--forte-separator-min-lengthLength floor for a vertical rule with nothing to stretch against1lh
--forte-separator-label-gapSpace between the label and the half-line either side of itvar(--forte-space-3)
--forte-separator-label-colorLabel colorvar(--forte-color-foreground-muted)
--forte-separator-label-font-sizeLabel font sizevar(--forte-font-size-1)
--forte-separator-label-font-weightLabel font weightvar(--forte-font-weight-medium)

State is on data-orientation and data-variant, with data-labeled beside them when there is a label, so a consumer can reach all three from plain CSS or a Tailwind arbitrary variant (data-[orientation=vertical]:...) without wrapping the component. The label itself is data-forte="separator-label".

API reference

Props for Separator
PropTypeDefaultDescription
childrenReactNodeA label set into the line — `or` between two ways to sign in, a date between two runs of messages. The rule splits around it, one half either side, in both orientations. Text is the usual case, but anything renders: an icon, a `Badge`, a `Kbd`. A labeled rule is also *named* by its label. The root gets `aria-labelledby` pointing at it, so a screen reader announces the label as the separator's name instead of passing over it — `separator` is a role whose children are presentational, so text left loose inside one is not guaranteed to be exposed at all. Pass an `aria-label` or `aria-labelledby` of your own to name it differently. Under `decorative` there is no name to give: the role goes, and the label stays in the tree as plain text. Not with `render={<hr />}` — `<hr>` is a void element and cannot hold one.
classNamestringAdditional class name(s). Applied after the internal styles so consumer utilities (e.g. Tailwind) win without needing `!important`.
decorativebooleanfalseDrops `role="separator"`, leaving the line visible but absent from the accessibility tree. Use it when the grouping is already conveyed some other way — a heading, a landmark, a list — and the rule is only reinforcing it visually. Announcing a boundary that the structure already communicates makes a screen reader read the page's decoration out loud.
orientationSeparatorOrientationhorizontalWhich way the rule runs — and therefore which axis it separates. A `horizontal` rule is a line across the inline axis dividing stacked content; a `vertical` one is a line down the block axis dividing content in a row. It is also what Base UI reports as `aria-orientation`, so it is a semantic choice, not only a visual one.
variantSeparatorVariantsolidThe line style. A rule has exactly one visual dimension, so this is the whole of it: `solid` for structural divisions, `dashed` or `dotted` for softer, more provisional ones (a drop zone's edge, an optional section).

Everything else passes through to Base UI's Separator.