Separator
A thin line that divides related content. It can be horizontal or vertical, carry a centered label, fade toward a transcript label, or become a quiet timeline note.
Orientations
Horizontal splits stacked regions. Vertical splits items in a row and stretches to the row height.
Project details
Meadow is a shared workspace for the spring planting plan.
Button groups
tone="input" matches control borders. The separator runs across the group, so it is vertical in a row and horizontal in a column.
Page 1 of 3
Page 1 of 3
Form sections
Separator with children centers short text on the line. Children that render nothing keep the same spacing.
Item lists
Separators go between rows only, so loading and empty lists never show a stray line.
Planting schedule.pdf
Updated today by Maya
Seed order.csv
Updated yesterday by Leo
Greenhouse watering rotation and volunteer handbook.docx
Updated last week by Priya
Sidebar
SidebarSeparator insets the line to the menu edges.
Usage
import { Separator } from "@tulipfarm/sprout/separator";
<p>Project details</p>
<Separator />
<div className="flex items-center gap-3">
<span>Meadow</span>
<Separator orientation="vertical" />
<span>Updated today</span>
</div>
<div role="group" aria-label="Pages" className="flex">
<Button variant="ghost">Previous</Button>
<Separator tone="input" orientation="vertical" />
<Button variant="ghost">Next</Button>
</div>
<Separator>or</Separator>orientation is "horizontal" (default) or "vertical". A horizontal line fills the width. A vertical line stretches to the height of its flex row. tone is "default", which uses --sprout-line, or "input", which uses --sprout-input to match control borders inside button groups. In a column of buttons, use a horizontal separator.
Separator has no margin. Add spacing with className, for example my-2 between list rows. className may be a function of { orientation }, and the Base UI render prop swaps the element.
Variants
variant and children pick the shape. The root always gets data-slot="separator" and a data-variant.
"line"(default) draws a bare 1px rule in either orientation.- A line with
childrencenters short content such as "or". Itsdata-variantis"label". "fade"fades the line toward a centered text label. Use it to mark a point in a transcript."marker"is a quiet, full-width timeline note with an icon and text."marker-border"adds a line under the marker row. Use it to head a group of events.
Labeled separator
Pass children to center short text such as "or" or a section name on a horizontal line. The labeled row takes div props. Children that render nothing, such as false, keep the same 20px height, so form spacing stays even. Long text stays on one line and ends with an ellipsis.
Put a SeparatorIcon before the text for an icon and label between two lines. Use this to split a timeline by day.
Fade
<Separator variant="fade">Auto compacted</Separator>
<Separator variant="fade">Compacted</Separator>With variant="fade", children is a required string. It is shown between the lines and also names the separator. The fade fills the width of its container and has no margin, so add spacing with the parent's gap or with className. Otherdiv props and the Base UI render prop pass through.
The lines fade in from the edges toward the label. On hover, a soft highlight sweeps across the lines and label once. Long labels stay on one line and end with an ellipsis.
Fade labels
Faded lines with a centered label. These are the two labels the chat uses after a compaction.
Chat compaction
A finished compaction collapses to a fade separator between messages. While the handoff is still being written, the chat shows a status row instead.
Narrow columns
The lines shrink first. If a label still does not fit, it stays on one line and ends with an ellipsis.
Marker
import {
Separator,
SeparatorContent,
SeparatorIcon,
} from "@tulipfarm/sprout/separator";
import { BookOpen } from "reicon-react/icons/BookOpen";
import { Calendar } from "reicon-react/icons/Calendar";
import { History } from "reicon-react/icons/History";
<Separator variant="marker">
<SeparatorIcon><BookOpen size={16} /></SeparatorIcon>
<SeparatorContent>Used skill Weekly report · 3f9a2c1b</SeparatorContent>
</Separator>
<Separator>
<SeparatorIcon><Calendar /></SeparatorIcon>
Today
</Separator>
<Separator variant="marker-border">
<SeparatorIcon><History /></SeparatorIcon>
<SeparatorContent>Yesterday · 4 events</SeparatorContent>
</Separator>A marker renders a div with 14px muted text and 8px between its parts. "marker-border" adds a 1px line and 8px of space under the row. There is one size.
SeparatorIcon is a 16px slot. An svg inside it is 16px unless you give it a size class. SeparatorContentholds the marker text. Long words wrap, so the row never overflows its column.
Marker variants
One 14px text size with a 16px icon. Pick the row by how strongly the note should split the timeline.
variant="marker"Icon and text on one quiet row. Chat uses it for skill use.<Separator>An icon and text centered between two lines. Use it to split a timeline by day.variant="marker-border"A line under the row. Use it as a heading over a group of events.Chat skill use
Sample chat parts. A skill-use part renders a marker with a book icon, the skill name, and an 8-character revision. A day part renders a labeled Separator.
Timeline marker variants
The internal playground row. Each row has a check icon and its name with “Today”.
Links
Links inside SeparatorContent, or a whole marker rendered as a link, are underlined and darken on hover and focus.
Long content
In narrow columns marker text wraps. A labeled row stays on one line and ends with an ellipsis.
Marker links
<Separator variant="marker">
<SeparatorContent>
Robin edited the brief · <a href="/changes">View changes</a>
</SeparatorContent>
</Separator>
<Separator variant="marker" render={<a href="/skills/weekly-report" />}>
<SeparatorIcon><BookOpen size={16} /></SeparatorIcon>
<SeparatorContent>Open skill Weekly report</SeparatorContent>
</Separator>A link directly inside SeparatorContent is underlined. So is a marker rendered as a link with render. Both turn to the text color on hover and keyboard focus and get a focus ring.
Sidebar
import { SidebarSeparator } from "@tulipfarm/sprout/sidebar";
<SidebarGroup>…</SidebarGroup>
<SidebarSeparator />
<SidebarGroup>…</SidebarGroup>SidebarSeparator is a Separator inset 8px from each edge, withdata-sidebar="separator". SidebarHeader and SidebarFooter already draw their own border, so use it between groups.
Accessibility
A line renders role="separator" with aria-orientation. It is not focusable and does not stop keyboard movement between the controls around it. If a line is only decoration, pass role="none".
The text in a labeled separator is read as normal text. The second line is hidden from screen readers. SeparatorIcon is aria-hidden, so put the meaning in words.
A fade separator uses its label as its aria-label. The highlight copy is hidden from screen readers. The hover sweep only runs on devices that can hover, and never when reduced motion is requested.
A marker has no role and does not take focus. Screen readers read its content as plain text. In forced colors mode the marker border uses the system text color.
Line and link colors change in 120ms and do not animate when reduced motion is requested.
Theme tokens
Lines use --sprout-line, and tone="input" uses--sprout-input. Labels and marker text use --sprout-muted. Fade labels are --sprout-text-xs, and the hover highlight uses --sprout-text. Hovered and focused marker links use--sprout-text, and the focus ring uses --sprout-focus. Override them in light and dark modes like any other Sprõut token.