component

Separator

A rule between sections, optionally interrupted by a label. Separator is the shared primitive behind the divider styling that used to be duplicated privately inside Group, Panel, Menu, ListBox, Toast and Breadcrumb — reach for it whenever a boundary needs to be drawn rather than implied by spacing alone.

It draws the line on its own border, so a plain rule is a single element with nothing nested inside it. Add a label and the layout switches automatically: the border is dropped and the rule is redrawn as two segments flanking the text. That switch is structural (:has()), not a prop, so there is no hasLabel flag to keep in sync.

Orientation

horizontal (the default) splits stacked content. vertical stretches to its parent’s cross axis, so it needs a flex or grid parent with a definite height — inside a toolbar or a row of inline metadata, for example.

Above the rule

Below the rule

LeftRight
---
import Separator from "../Separator.astro";
import { stack, flex } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <div class={stack({ gap: "sm", direction: "column" })}>
    <p>Above the rule</p>
    <Separator />
    <p>Below the rule</p>
  </div>

  <div class={flex({ gap: "sm", align: "center", height: "3rem" })}>
    <span>Left</span>
    <Separator orientation="vertical" />
    <span>Right</span>
  </div>
</div>

Emphasis and Pattern

emphasis picks the weight and feedback picks the hue — the same split as the rest of the system. The three levels map onto the palette’s real border tokens: subtle is the everyday hairline between sections, bold is for a structural split, and accent tints the rule (and its label) with the active feedback colour. pattern changes the stroke itself; a dashed rule reads well as a “drop something here” or “content continues” boundary.

---
import Separator from "../Separator.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "lg", direction: "column" })}>
  <Separator emphasis="subtle" />
  <Separator emphasis="bold" />
  <Separator emphasis="accent" feedback="primary" />
  <Separator pattern="dashed" emphasis="bold" />
  <Separator pattern="dotted" emphasis="bold" />
</div>

Labelled

Children become the label — <Separator>Section</Separator> — because a separator has exactly one content area. With no children no label element is rendered at all, which matters: an empty span would trip the labelled layout and blank the line.

labelAlign moves the text along the rule. center splits the line evenly; start and end leave a short stub on the near side, sized by --separator-inset.

---
import Separator from "../Separator.astro";
import { stack } from "@pindoba/styled-system/patterns";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <Separator labelAlign="start">Start</Separator>
  <Separator labelAlign="center">Center</Separator>
  <Separator labelAlign="end">End</Separator>
  <Separator emphasis="bold" pattern="dashed">Dashed with a label</Separator>
</div>

Accessibility

A separator is announced by default: the root carries role="separator" plus an aria-orientation, so assistive tech reports the boundary. Pass decorative when the split is already conveyed some other way — a heading, a landmark, a list — and the extra announcement would only be noise. A decorative rule is removed from the accessibility tree entirely (role="none"), and its aria-orientation is dropped with it, since that attribute is meaningless without the role.

Customization

Thickness and the label-side inset are CSS variables rather than variants, so retune them per call site by redefining --separator-thickness and --separator-inset instead of reaching for a new prop. passThrough.root and passThrough.label take Panda style objects and raw HTML attributes as usual.

---
import Separator from "../Separator.astro";
import { stack } from "@pindoba/styled-system/patterns";
import { css } from "@pindoba/styled-system/css";
---

<div class={stack({ gap: "xl", direction: "column" })}>
  <Separator
    passThrough={{
      root: { style: css.raw({ "--separator-thickness": "3px" }) },
    }}
    emphasis="bold"
  />

  <Separator
    labelAlign="start"
    passThrough={{
      root: { style: css.raw({ "--separator-inset": "3rem" }) },
      label: { style: css.raw({ fontWeight: "bold", color: "primary.text" }) },
    }}
  >
    Retuned inset
  </Separator>

  <Separator
    decorative
    passThrough={{ root: { props: { "data-decorative": "true" } } }}
  />
</div>
props · 10 shown · 10 total
children slot svelte
Snippet

Optional label rendered inline, interrupting the rule. Omit it for a plain rule.

decorative
boolean
default false

Whether the separator is purely visual. A semantic separator (the default) is exposed as `role="separator"` with an orientation, so assistive tech can announce the boundary. Set `decorative` when the split is already conveyed some other way — a heading, a landmark, a list — and the extra announcement would only be noise.

element binding svelte
HTMLDivElementnull

Bound reference to the root element (`bind:this`).

emphasis
"bold""subtle""accent"
default "subtle"

Weight of the rule: `subtle` for the everyday hairline between sections, `bold` where the split is structural, `accent` to tint it with the active `colorPalette`.

feedback
"primary""neutral""success""warning""danger""inherit"
default "neutral"

Semantic palette the rule draws from, forwarded as `colorPalette` — so `emphasis` picks the weight and `feedback` picks the hue. Also tints the label, which inherits the palette's custom properties.

labelAlign
"end""start""center"
default "center"

Where the label sits along the rule. Has no effect without a label.

orientation
"horizontal""vertical"
default "horizontal"

Axis the rule runs along. A `vertical` separator stretches to its parent's cross axis, so it needs a flex or grid parent with a definite height.

passThrough
SeparatorPassThrough<RootElementAttributes>

Per-slot style and HTML-attribute overrides.

pattern
"solid""dashed""dotted"
default "solid"

Stroke style of the rule.

spacing
"sm""md""lg""none""xs""3xs""2xs"
default "none"

Space reserved on both sides of the rule, along its cross axis — block margin when horizontal, inline margin when vertical.

Plus all standard <div> HTML attributes.

Type

  • Components
  • Blocks