Skip to content

Divider

One flex box and its two pseudo-elements. Each one grows into the space the label leaves, so a divider with a label and a divider without one are the same element with the same rule — and neither of them runs a line of JavaScript.

  • Stable
  • React 19
  • Zero JS
  • One DOM node
Code
<Divider />
<Divider>OR</Divider>
<div class="wayra-divider" role="separator" data-orientation="horizontal"></div>
<div class="wayra-divider" role="separator" data-orientation="horizontal" data-placement="center">OR</div>

A divider separates two blocks of content that already belong together — sections of a form, groups in a menu, an account form and the single-sign-on buttons under it. It is chrome, not content: if the two sides need explaining, they need a heading, not a line.

Children are the label, and they are the only reason the divider has a gap. Leave them out and the two halves close back up into one continuous line.

Code
<Divider placement="start">start</Divider>
<Divider placement="center">center</Divider>
<Divider placement="end">end</Divider>
<div class="wayra-divider" role="separator" data-orientation="horizontal" data-placement="start">start</div>
<div class="wayra-divider" role="separator" data-orientation="horizontal" data-placement="center">center</div>
<div class="wayra-divider" role="separator" data-orientation="horizontal" data-placement="end">end</div>

placement cuts the growth of one side to a short stub, and the label follows it. On a divider with no label there is nothing to place, so the attribute is not rendered at all — data-placement in the DOM always means there is a label in it.

Copy Paste

A vertical divider stretches to its parent's height — give it one.

Code
<div style={{ display: 'flex', alignItems: 'center', gap: '1rem', height: '2.5rem' }}>
<span>Copy</span>
<Divider orientation="vertical" />
<span>Paste</span>
</div>
<div style="display: flex; align-items: center; gap: 1rem; height: 2.5rem">
<span>Copy</span>
<div class="wayra-divider" role="separator" aria-orientation="vertical" data-orientation="vertical"></div>
<span>Paste</span>
</div>

Vertical flips the flex direction and moves the hairline to the inline edge of each pseudo-element. The divider stretches to fill its parent, which is what makes a row of toolbar buttons line up; in a parent with no height there is nothing to stretch into and nothing to see.

The class and the data-* attributes are the API. Hand-written markup gets the same line, with no React anywhere:


Code
<Divider>OR</Divider>
<Divider />
<div class="wayra-divider" role="separator" data-orientation="horizontal" data-placement="center">OR</div>
<hr class="wayra-divider" />

For the label-less case an <hr> is enough. It is already a separator, so it needs no role and no attributes — only the class. The base rule clears the 1px inset box and the block margins a browser gives an <hr>, so the two hairlines are the only thing left drawn. An <hr> cannot hold a label, which is why the component itself is always a <div> rather than switching elements underneath you.

Two custom properties are meant to be overridden, per instance or per theme:

Property Default What it does
--wayra-divider-color var(--wayra-color-base-300) The color of both lines.
--wayra-divider-line 0.125rem Their thickness. A lighter theme sets 1px here and changes nothing else.

DividerProps extends ComponentProps<"div"> minus color and role. Everything else lands on the root, which is the only element there is.

Prop Type Default Description
orientation "horizontal" | "vertical" "horizontal" Which way the line runs.
placement "start" | "center" | "end" "center" Where the label sits. Ignored without one.
children ReactNode — The label. Without it, a bare line.
unstyled boolean false Drops the class, keeps the data-*.

There is no color prop and no dashed variant. A separator organizes a layout, it does not report state, so eight semantic roles on one would be API nobody reaches for — and React’s legacy color attribute is dropped along with it so it cannot be mistaken for that API. If a real case turns up, data-color can be added later without breaking anything.

  • role="separator" is pinned and the element is not focusable. This is the structural flavour of the role, the one that organizes a layout, not the draggable splitter.
  • A separator takes no accessible name. There is no aria-label in any example on this page, and the automated gate does not ask for one.
  • aria-orientation is rendered only when vertical. Horizontal is the role’s own default, and repeating what the platform already says adds noise and nothing else.
  • The label is decoration. separator takes presentational children, so do not put anything in the label that is not also in the content on either side of it.
  • Contrast: the hairline is base-300, 1.27:1 against base-100 in the default theme — deliberately faint, and legal here.