component
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.
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
---
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 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>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>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.
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>Optional label rendered inline, interrupting the rule. Omit it for a plain rule.
falseWhether 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.
Bound reference to the root element (`bind:this`).
"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`.
"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.
"center"Where the label sits along the rule. Has no effect without a label.
"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.
Per-slot style and HTML-attribute overrides.
"solid"Stroke style of the rule.
"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.