# Separator

> A hairline that divides content horizontally or vertically, with an optional label and a decorative mode for purely visual lines.

Docs: https://hextaui.com/docs/separator
Markdown: https://hextaui.com/docs/separator.md

```tsx title="components/examples/separator/demo.tsx"
import { Separator } from "@/components/ui/separator"

export function SeparatorDemo() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-4 text-sm">
      <div className="flex flex-col gap-1">
        <h4 className="font-medium">HextaUI</h4>
        <p className="text-muted-foreground">
          Components that feel great to use and to write.
        </p>
      </div>
      <Separator />
      <div className="flex h-5 items-center gap-4">
        <a href="#">Docs</a>
        <Separator orientation="vertical" />
        <a href="#">Components</a>
        <Separator orientation="vertical" />
        <a href="#">Source</a>
      </div>
    </div>
  )
}
```

## Installation

### CLI

```bash
npx shadcn@latest add https://hextaui.com/r/separator.json
```

This adds the component, the HextaUI theme tokens and any HextaUI components it depends on.

### Manual

Add the HextaUI theme tokens (https://hextaui.com/docs/installation#theme) to your global CSS if you haven't yet, then install the dependencies.

```bash
pnpm add @base-ui/react cn
```

Copy and paste the following code into your project.

```tsx title="components/ui/separator.tsx"
"use client"

import * as React from "react"
import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
import { cn } from "cn"

type SeparatorAlign = "start" | "center" | "end"

type SeparatorOrientation = NonNullable<SeparatorPrimitive.Props["orientation"]>

type SeparatorProps = SeparatorPrimitive.Props & {
  decorative?: boolean
  align?: SeparatorAlign
}

const lineClassName: Record<SeparatorOrientation, string> = {
  horizontal:
    "h-(--hairline) w-full shrink-0 bg-border forced-colors:bg-canvas-text",
  vertical:
    "w-(--hairline) shrink-0 self-stretch bg-border forced-colors:bg-canvas-text",
}

const labelledClassName: Record<SeparatorOrientation, string> = {
  horizontal:
    "flex w-full shrink-0 items-center gap-3 text-xs text-muted-foreground before:h-(--hairline) before:min-w-4 before:flex-1 before:bg-border after:h-(--hairline) after:min-w-4 after:flex-1 after:bg-border data-[align=end]:after:hidden data-[align=start]:before:hidden",
  vertical:
    "flex shrink-0 flex-col items-center gap-3 self-stretch text-xs text-muted-foreground before:min-h-4 before:w-(--hairline) before:flex-1 before:bg-border after:min-h-4 after:w-(--hairline) after:flex-1 after:bg-border data-[align=end]:after:hidden data-[align=start]:before:hidden",
}

const labelAlignClassName: Record<SeparatorAlign, string> = {
  start: "text-start",
  center: "text-center",
  end: "text-end",
}

function mergeClassName<State>(
  base: string,
  className: string | ((state: State) => string | undefined) | undefined
) {
  return typeof className === "function"
    ? (state: State) => cn(base, className(state))
    : cn(base, className)
}

function hasContent(children: React.ReactNode) {
  return React.Children.toArray(children).some(
    (child) => typeof child !== "string" || child.trim() !== ""
  )
}

function Separator({
  className,
  orientation = "horizontal",
  decorative = false,
  align = "center",
  children,
  ...props
}: SeparatorProps) {
  const labelled = hasContent(children)
  const semantics = labelled
    ? { role: undefined, "aria-orientation": undefined }
    : decorative
      ? { role: "none", "aria-orientation": undefined }
      : {}

  return (
    <SeparatorPrimitive
      data-slot="separator"
      data-content={labelled ? "" : undefined}
      data-align={labelled ? align : undefined}
      orientation={orientation}
      className={mergeClassName(
        (labelled ? labelledClassName : lineClassName)[
          orientation === "vertical" ? "vertical" : "horizontal"
        ],
        className
      )}
      {...semantics}
      {...props}
    >
      {labelled ? (
        <span
          data-slot="separator-label"
          className={cn(
            "flex max-w-full min-w-0 items-center gap-1.5 text-pretty wrap-anywhere [&>svg]:size-3.5 [&>svg]:shrink-0",
            labelAlignClassName[align]
          )}
        >
          {children}
        </span>
      ) : null}
    </SeparatorPrimitive>
  )
}

export { Separator }
export type { SeparatorAlign, SeparatorProps }
```

Update the import paths to match your project setup.

## Usage

```tsx
import { Separator } from "@/components/ui/separator"
```

```tsx
<Separator />
<Separator orientation="vertical" />
<Separator>Or continue with</Separator>
```

The line is one physical pixel thick on every screen, the same hairline as borders, so it lines up with cards and inputs around it. Space it with the parent's `gap` or a margin.

## Examples

### Vertical

With `orientation="vertical"` the line stretches to the height of its flex row. Outside a flex row, give it a height.

```tsx title="components/examples/separator/vertical.tsx"
import { Separator } from "@/components/ui/separator"

export function SeparatorVertical() {
  return (
    <div className="flex items-center gap-4 text-sm">
      <div className="flex flex-col">
        <span className="font-medium tabular-nums">2,481</span>
        <span className="text-muted-foreground">Stars</span>
      </div>
      <Separator orientation="vertical" />
      <div className="flex flex-col">
        <span className="font-medium tabular-nums">164</span>
        <span className="text-muted-foreground">Forks</span>
      </div>
      <Separator orientation="vertical" />
      <div className="flex flex-col">
        <span className="font-medium tabular-nums">38</span>
        <span className="text-muted-foreground">Contributors</span>
      </div>
    </div>
  )
}
```

### Label

Children sit in the middle of the line, with the line filling the space on both sides.

```tsx title="components/examples/separator/label.tsx"
import { Button } from "@/components/ui/button"
import { Separator } from "@/components/ui/separator"

export function SeparatorLabel() {
  return (
    <div className="flex w-full max-w-xs flex-col gap-4">
      <Button>Continue with email</Button>
      <Separator>Or continue with</Separator>
      <div className="grid grid-cols-2 gap-2">
        <Button variant="outline">GitHub</Button>
        <Button variant="outline">Google</Button>
      </div>
    </div>
  )
}
```

### Align

`align` moves the label to the `start` or `end`, which suits section and date headers. Icons are sized to the text.

```tsx title="components/examples/separator/align.tsx"
import { IconCalendar } from "@tabler/icons-react"

import { Separator } from "@/components/ui/separator"

export function SeparatorAlign() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-6">
      <Separator align="start">
        <IconCalendar aria-hidden="true" />
        Today
      </Separator>
      <Separator>Yesterday</Separator>
      <Separator align="end">Last week</Separator>
    </div>
  )
}
```

### Vertical label

A vertical separator with a label keeps the text upright and draws the line above and below it.

```tsx title="components/examples/separator/vertical-label.tsx"
import { Button } from "@/components/ui/button"
import { Separator } from "@/components/ui/separator"

export function SeparatorVerticalLabel() {
  return (
    <div className="flex items-stretch gap-4">
      <div className="flex w-32 flex-col gap-2">
        <Button variant="outline">Upload file</Button>
        <Button variant="outline">Browse library</Button>
      </div>
      <Separator orientation="vertical">or</Separator>
      <div className="flex w-32 items-center justify-center rounded-lg border border-dashed p-4 text-center text-sm text-muted-foreground">
        Drop a file here
      </div>
    </div>
  )
}
```

### Decorative

`decorative` hides a purely visual line from screen readers, so they don't announce a separator between rows that already read well on their own.

```tsx title="components/examples/separator/decorative.tsx"
import { Separator } from "@/components/ui/separator"

export function SeparatorDecorative() {
  return (
    <div className="flex w-full max-w-xs flex-col gap-3 rounded-xl border p-4 text-sm">
      <div className="flex items-center justify-between">
        <span className="text-muted-foreground">Subtotal</span>
        <span className="tabular-nums">$48.00</span>
      </div>
      <div className="flex items-center justify-between">
        <span className="text-muted-foreground">Shipping</span>
        <span className="tabular-nums">$4.00</span>
      </div>
      <Separator decorative />
      <div className="flex items-center justify-between font-medium">
        <span>Total</span>
        <span className="tabular-nums">$52.00</span>
      </div>
    </div>
  )
}
```

### Inline

Use `render` to output a `<span>` where a `<div>` isn't allowed, like inside a paragraph.

```tsx title="components/examples/separator/render.tsx"
import { Separator } from "@/components/ui/separator"

export function SeparatorRender() {
  return (
    <p className="text-sm text-muted-foreground">
      <span className="inline-flex h-4 items-center gap-2 align-middle">
        <span>Ada Park</span>
        <Separator orientation="vertical" decorative render={<span />} />
        <time dateTime="2026-10-05">Oct 5, 2026</time>
        <Separator orientation="vertical" decorative render={<span />} />
        <span>4 min read</span>
      </span>
    </p>
  )
}
```

### Long content

Long labels wrap and unbroken strings break, while a short stretch of line stays visible on each side.

```tsx title="components/examples/separator/long-content.tsx"
import { Separator } from "@/components/ui/separator"

export function SeparatorLongContent() {
  return (
    <div className="flex w-full max-w-72 flex-col gap-6">
      <Separator>
        Messages before you joined the channel are kept for ninety days
      </Separator>
      <Separator align="start">
        https://hextaui.com/docs/components/separator/very-long-anchor
      </Separator>
    </div>
  )
}
```

### Right to left

Start and end follow the reading direction.

```tsx title="components/examples/separator/rtl.tsx"
import { Separator } from "@/components/ui/separator"

export function SeparatorRtl() {
  return (
    <div dir="rtl" className="flex w-full max-w-sm flex-col gap-6 text-sm">
      <Separator align="start">اليوم</Separator>
      <div className="flex h-5 items-center gap-4">
        <a href="#">الوثائق</a>
        <Separator orientation="vertical" />
        <a href="#">المكونات</a>
        <Separator orientation="vertical" />
        <a href="#">المصدر</a>
      </div>
    </div>
  )
}
```

## Accessibility

- A plain separator has `role="separator"` and `aria-orientation`, like an `<hr>`.
- With `decorative`, it gets `role="none"` and screen readers skip it.
- A separator with a label has no role. The separator role would make its text presentational, so the label is read as plain text instead.

## API reference

Built on the Base UI Separator. Renders a `<div>` and accepts its attributes.

### Separator

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` |  |
| `decorative` | `boolean` | `false` | Hide the line from screen readers when it is only visual. |
| `children` | `ReactNode` | – | A label drawn in the line. Leave it out for a plain line. |
| `align` | `"start" \| "center" \| "end"` | `"center"` | Where the label sits along the line. |
| `className` | `string \| (state) => string` | – |  |
| `render` | `ReactElement \| (props, state) => ReactElement` | `<div>` |  |

| Attribute | Description |
| --- | --- |
| `data-slot="separator"` | Target separators in CSS. |
| `data-orientation` | "horizontal" or "vertical". |
| `data-content` | Present when the separator has a label. |
| `data-align` | The label's alignment, when there is a label. |
| `data-slot="separator-label"` | The element that wraps the label. |

## Notes for AI assistants

- Install a component with the shadcn CLI: `npx shadcn@latest add https://hextaui.com/r/<name>.json`. It adds the source, the HextaUI theme tokens and any HextaUI components it depends on. `https://hextaui.com/r/all.json` installs every component.
- The code is then owned by the project, like shadcn/ui. There is no HextaUI npm package. HextaUI is MIT licensed and free for personal and commercial use.
- Behavior and accessibility come from Base UI (`@base-ui/react`). Compose with the `render` prop, not `asChild`.
- Styling uses Tailwind CSS v4 with theme tokens. Merge classes with `cn` from the `cn` package.
- Icons come from `@tabler/icons-react`.
- Import components from `@/components/ui/<name>`, hooks from `@/hooks/<name>` and utilities from `@/lib/<name>`.

Every HextaUI doc: https://hextaui.com/llms.txt
