---
title: Separator
description: A rule with two directions and an accessibility decision: announced when it separates content, silent when it is furniture.
source: https://adamjurek.com/components/separator
---

## Home


Separator draws a rule in either direction, horizontal or vertical. Pass
`decorative` for a purely visual divider that is hidden from screen readers;
leave it off when the rule genuinely separates content and should be
announced as one.

<!-- ::start:showcase demo="separator" height="380" -->
<!-- ::end:showcase -->

## Why it is built this way

Whether a rule gets announced is an accessibility decision, not a styling
one, so `decorative` swaps the actual element rather than just its look: a
real `<hr>` when it separates content, a styled, `aria-hidden` span when it
is furniture. A data attribute alone could never have carried that
distinction honestly.


## Install

<!-- ::start:tabs -->

### TanStack

```shell
tanstack add https://adamjurek.com/r/tanstack/separator.json
```

### shadcn

```shell
pnpm dlx shadcn@latest add https://adamjurek.com/r/shadcn/separator.json
```

### pnpm

```shell
pnpm add @sushindustries/ui @sushindustries/atoms
```

<!-- ::end:tabs -->

## What you get

| | |
| --- | --- |
| Version | 0.1.0 |
| Category | layout · Page structure |
| Files | `separator.tsx` |
| Dependencies | None |
| Tags | divider, no-deps |

> [!NOTE] No runtime dependencies
> It brings nothing with it beyond the stylesheet.

## Get Started


Install commands are on Home, attached from the registry - they are not written
here, because a second copy is a copy that goes stale. This tab starts after the
install worked.

## Use it

```tsx
import { Separator } from "@sushindustries/ui";

export function Menu() {
	return (
		<nav className="flex items-center gap-3">
			<a href="/components">Components</a>
			<Separator orientation="vertical" decorative />
			<a href="/packages">Packages</a>
		</nav>
	);
}
```

## What you should see

A thin rule between the two links. Horizontal (the default) renders as an
actual `<hr>` unless `decorative` is set, in which case it's a styled
`<span>` that screen readers skip entirely. Vertical needs a height to show
against - inside a row with no defined height it collapses to nothing
visible.

## If nothing happens

A vertical separator with no visible line almost always means its container
has no height for it to span - `align-items: stretch` on a flex row, or an
explicit height, is what gives it something to be as tall as.


## Guides


## Composing it

A vertical separator needs a height to span - it has none of its own. Give
the row `align-items: stretch`, or give the separator's parent an explicit
height; without either, `orientation="vertical"` renders a line with nothing
to be tall against.

## Variants

`orientation` writes `data-orientation` on the element, the same pattern
every variant in this library uses - a prop, never a second class:

```tsx
<Separator orientation="vertical" />
```

```css
.separator[data-orientation="vertical"] {
	width: 1px;
	height: 100%;
}
```

`decorative` isn't a variant in that sense - it swaps the actual element
between `<hr>` and `<span>`, because whether a rule is announced is an
accessibility decision, not a look.


## API


<!-- generated:api -->

## Props

| Prop | Type | Default | Does |
| --- | --- | --- | --- |
| `orientation?` | `"horizontal" \| "vertical"` | `"horizontal"` | Vertical needs a height from its container; horizontal is the default. |
| `decorative?` | `boolean` | `false` | Purely visual dividers should not be announced. |

<!-- /generated:api -->

## Notes

`decorative` changes which element renders, not just an ARIA attribute on
the same one - `true` produces a `<span aria-hidden="true">`, `false`
produces a real `<hr>`. There's no in-between where an `<hr>` is hidden from
screen readers or a `<span>` is announced; pick the element by picking the
prop.

`orientation="vertical"` depends entirely on its container providing a
height, as covered in Guides - the prop only writes the attribute the
stylesheet reads.


## Examples


Examples are the tab where the component is shown doing a job, not
demonstrating a prop. The API tab already lists the props.

<!-- ::start:showcase demo="separator" height="420" -->
<!-- ::end:showcase -->

Press Compare. The frames are real viewports, so a layout that breaks at 320
breaks here too rather than in somebody's hands.

## In a page

```tsx
import { Separator } from "@sushindustries/ui";

export function Toolbar() {
	return (
		<div className="flex items-center gap-3">
			<button type="button">Save</button>
			<Separator orientation="vertical" decorative />
			<button type="button">Publish</button>
		</div>
	);
}
```

## What this example is not

A guarantee the line shows up on its own. This toolbar works because
`.flex.items-center` gives every child the row's own height to stretch
against - drop the separator into a row without that and it's back to
needing an explicit height, per Guides.
