Browse docs
Browse docs
A visual line that says "things on one side, different things on the other". Two modes: a plain line, or a labeled separator with the line on both sides of the label (<Divider>OR</Divider> — the universal sign-in pattern).
import { Divider, Typography } from '@dashforge/tw';
{/* Plain line */}
<Divider />
{/* Labeled — "OR" pattern */}
<Divider>
<Typography variant="overline">OR</Typography>
</Divider>{/* Between sections */}
<Typography variant="h2">Profile</Typography>
<Divider sx="my-6" />
<Typography variant="h2">Notifications</Typography>
{/* OR pattern in sign-in */}
<Button color="primary" fullWidth>Continue with Google</Button>
<Divider sx="my-4">OR</Divider>
<TextField name="email" label="Email" />
{/* Vertical inside a Stack row */}
<Stack direction="row" align="center" gap={3}>
<Typography>Item A</Typography>
<Divider orientation="vertical" sx="h-6" />
<Typography>Item B</Typography>
</Stack>divider propBoth insert visual separators between things. Use which one:
| Scenario | Use |
|---|---|
| You want a separator BETWEEN every pair of children in a list | <Stack divider={<Divider />}> — the prop handles N-1 insertion |
| You want ONE separator at a specific place | <Divider /> standalone |
| You need an "OR" label between two pieces of content | <Divider>OR</Divider> (Stack's divider is meant for repeating separators, not labels) |
| You want vertical separator between flex row items | Either — Stack's divider works for repeating, standalone Divider for one-off |
Section A — first paragraph
Section B — after solid divider
Section C — after dashed divider
import { Divider, Stack, Typography } from '@dashforge/tw';
<Stack gap={3}>
<Typography variant="body2">Section A — first paragraph</Typography>
<Divider />
<Typography variant="body2">Section B — after solid divider</Typography>
<Divider variant="dashed" />
<Typography variant="body2">Section C — after dashed divider</Typography>
</Stack><Divider /> {/* solid (default) */}
<Divider variant="dashed" />
<Divider variant="dotted" />Solid for the canonical separator. Dashed/dotted for "draft state", "less authoritative", or simply visual variety.
<Divider /> {/* neutral */}
<Divider color="primary" />
<Divider color="success" />
<Divider color="warning" />
<Divider color="danger" />Colored dividers are useful when the divider IS the message: a red one above an "Irreversible action" section, a green one between "Old plan" and "New plan" in an upgrade flow.
<Divider>OR</Divider>
<Divider><Typography variant="overline">OR</Typography></Divider>
<Divider>Continue with</Divider>
<Divider><strong>Section title</strong></Divider>Any node works as the label — string, Typography element, custom JSX. Recommended: <Typography variant="overline"> for short uppercase labels (matches the meta-text rhythm of section kickers).
The implementation renders two flex line segments either side of the label, with a small horizontal padding around the label so it doesn't kiss the lines.
<Divider align="start"> Title hugs left</Divider>
<Divider align="center">Title centered (default)</Divider>
<Divider align="end"> Title hugs right</Divider>start/end leave a short ~32px stub on the squashed side (rather than collapsing to zero) so the divider visually exists on both sides regardless of alignment.
{/* Between row items */}
<Stack direction="row" align="center" gap={3}>
<Typography variant="body2">Logged in</Typography>
<Divider orientation="vertical" sx="h-4" />
<Typography variant="body2" color="muted">2 minutes ago</Typography>
</Stack>
{/* As a column splitter */}
<Box fullHeight>
<Stack direction="row" fullHeight>
<NavSidebar />
<Divider orientation="vertical" />
<MainContent />
</Stack>
</Box>Vertical dividers need a height context — they take the height of their parent flex row via self-stretch. When that doesn't work (no flex parent), set sx="h-N" explicitly.
<Box variant="outlined" rounded="xl" p={6}>
<Typography variant="h3">Profile</Typography>
<Stack gap={3} sx="mt-4">
<TextField name="name" label="Display name" />
<TextField name="email" label="Email" />
</Stack>
<Divider sx="my-6" />
<Typography variant="h3">Security</Typography>
<Stack gap={3} sx="mt-4">
<Switch label="Two-factor authentication" />
</Stack>
</Box>import { Divider, Stack, Button, Typography } from '@dashforge/tw';
<Stack gap={4}>
<Button color="primary" fullWidth>Sign in with Google</Button>
<Divider>
<Typography variant="overline" color="muted">OR</Typography>
</Divider>
<Button variant="outline" fullWidth>Continue with email</Button>
</Stack><Stack gap={4}>
<Button color="primary" fullWidth>Continue with Google</Button>
<Button variant="outlined" fullWidth>Continue with GitHub</Button>
<Divider>
<Typography variant="overline" color="muted">or</Typography>
</Divider>
<Stack gap={3}>
<TextField name="email" type="email" label="Email" />
<TextField name="password" type="password" label="Password" />
<Button color="primary" fullWidth>Sign in</Button>
</Stack>
</Stack>Configure <Divider> defaults application-wide.
import { patchTheme } from '@dashforge/tw-theme';
patchTheme({
components: {
Divider: {
defaults: { orientation: 'horizontal', variant: 'solid', color: 'neutral' },
},
},
});Configurable axes (DividerVariantProps):
| Axis | Type | Notes |
|---|---|---|
orientation | 'horizontal' | 'vertical' | Line direction. |
align | 'start' | 'center' | 'end' | Label position when children is provided. |
variant | 'solid' | 'dashed' | 'dotted' | Line style. |
color | 'neutral' | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | Line color. |
Non-visual axes (children, flexItem, as, event handlers, ARIA) are not theme-configurable — content and per-instance semantics.
Precedence chain (lowest → highest):
defaultVariants from the internal dividerVariants recipe.theme.components.Divider.defaults (application-wide).<Divider variant="dashed" />) — wins over theme.sx — appended to the root and wins over conflicting classes via tailwind-merge.TypeScript: theme.components.Divider.defaults autocompletes to the four axes above.
Reactivity: useComponentDefaults('Divider') subscribes to the theme store — patchTheme re-renders every mounted instance inheriting the changed axis.
| Prop | Type | Default | Description |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'center' | Label position — only meaningful in labeled mode (when children is provided). |
children | ReactNode | — | Optional inline label. When present, the divider switches from "single line" to "two segments + label" layout — the canonical "OR" separator pattern between sign-in methods, section titled separators, etc. Accepts any node (string, Typography element, Stack with icon, etc.). Recommended: <Typography variant="overline">OR</Typography> for short uppercase labels. |
color | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'neutral' | 'neutral' | Semantic color of the line — drives the border color via the corresponding token palette. |
flexItem | boolean | — | In a flex Stack direction="row", a <Divider orientation="vertical"> with flexItem stretches to the row's cross-axis height (via self-stretch). Without it, vertical dividers may collapse to 0 height because there's nothing to anchor them.Implementation note: self-stretch is already applied on the vertical line segment by default in the TV — this prop is a no-op for now, kept for API parity with MUI's same flag (and as a forward-compatibility hook if we ever change the default). |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Line direction. 'horizontal' renders as <hr> (line-only) or a <div role="separator"> (labeled). 'vertical' renders as a <div> because <hr> can't be styled vertical cross-browser. |
sx | string | — | Utility classes appended to the variant chain. Resolved via tailwind-merge. Useful for one-off margin (sx="my-8") or a custom border weight (sx="border-t-2"). |
variant | 'solid' | 'dashed' | 'dotted' | 'solid' | Border style of the line segments. |
...rest | Omit<HTMLAttributes<HTMLElement>, 'className' | 'color' | 'children'> | — | Additional native attributes forwarded via Omit<HTMLAttributes<HTMLElement>, 'className' | 'color' | 'children'>. |
| Mode | Triggered when | Renders |
|---|---|---|
| Line-only | children is absent/null | <hr> (horizontal) or <div role="separator"> (vertical) with line classes |
| Labeled | children is provided | <div role="separator"> wrapping 2 <span aria-hidden> line segments + 1 <span> label |
role="separator" (implicit on <hr>, explicit on <div>)aria-orientation: "horizontal" or "vertical" always setaria-hidden (the separator role lives on the root; duplicating on children would confuse AT)<Divider> renders 1 element in line-only mode and 3 elements in labeled mode, but does not expose a public slotProps API — the two rendering modes each have their own TV recipe consumed internally.
Practical override guidance:
| Target | How |
|---|---|
| Line color / style / thickness | variant / color props, or sx |
| Label styling | Style the children node you pass in |
| Alignment of the label along the axis | align prop |
| Root container | sx (wins over recipe classes via tailwind-merge) |
The slotProps object pattern is reserved for compound components with independent named regions where per-slot injection would otherwise require multiple class-name conditionals (e.g. <DataGrid>, <Autocomplete>).
import { dividerVariants, dividerLineVariants } from '@dashforge/tw';
// dividerVariants({ orientation: 'horizontal', align: 'center' }) → root className
// dividerLineVariants({ orientation: 'horizontal', variant: 'solid', color: 'primary', segment: 'grow' }) → line classNameTwo TV recipes (root + line) because labeled mode renders 3 elements while line-only mode renders 1 — splitting keeps each catalogue small.
<hr> for horizontal line-only: gives implicit role="separator" for screen readers without an extra attribute. We zero out the UA default border via border-0 and re-apply ours.<div> because <hr> can't be vertical cross-browser-consistently. Same role="separator" is set explicitly.align="start" / "end" uses a 32px stub on the squashed side rather than collapsing to zero — keeps the divider visually present on both sides.flexItem is a no-op for now: self-stretch is already on the vertical line by default. Kept in the API for MUI Divider parity and as a forward-compat hook.<Stack divider={<Divider />}> instead of intermingling <Divider /> between every child. The Stack divider prop handles N-1 insertion cleanly.<Box sx="mt-12"> (more vertical space) communicates the section break without an explicit line.