Content divider
Divider separates or groups content with a line, a labelled line or a section band. Use it to break up long content.
Beta until Figma fixes the label colour binding and the “Seperator” spelling, and design confirms the merged action type and the vertical orientation (C39). Everything else on this page is implemented and tested.
Preview
Change the controls to try every type. The preview renders the real component and the code updates with it.
import { Divider } from '@nuton/ui'
<Divider type="text-line">or</Divider>Installation
Availability
@nuton/ui and @nuton/tokens are private workspace packages. They aren't published to a registry yet (D4: registry deferred; D12: distribution waits on the provenance review). Inside the Nuton monorepo, add them as workspace dependencies. The commands below apply once the packages are published.
1. Add the packages
pnpm add @nuton/ui @nuton/tokensnpm install @nuton/ui @nuton/tokensyarn add @nuton/ui @nuton/tokensPeer dependencies: react and react-dom 18 or later. Add @remixicon/react only if you put icon buttons in an action divider (D1).
2. Load tokens and component styles once
// app/layout.tsx (or your app's entry file)
import '@nuton/tokens/tokens.css' // --nu-* design tokens
import '@nuton/ui/styles.css' // component styles (uses the tokens)Divider has no state and works in server components.
Usage
import { Divider } from '@nuton/ui'
export function LessonNotes() {
return (
<article>
<p>Plants turn light into chemical energy in their chloroplasts.</p>
<Divider />
<p>Next, we look at how the Calvin cycle uses that energy.</p>
</article>
)
}- The default is a 1px
linein Stroke/Soft-200 that fills the width of its container. - Pick the
typeby what the divider carries: nothing (line,line-spacing), a label (text-line,text,solid-text,section) or controls (action). - Write labels in sentence case, such as “or” or “Today”. The uppercase types transform them, so screen readers still read a word, not letters.
- Dividers are decorative by default. Set
decorative={false}only for a real thematic break that people should hear. - Spacing around the divider comes from the parent layout (a gap or margin), not from the divider.
Variants and sizes
One type prop covers Figma's ten Type values. Every line is 1px Stroke/Soft-200, and the four button types share one action type that takes your own controls.
Line and line spacing
<Divider /> // line: 1px
<Divider type="line-spacing" /> // 1px line in a 4px bandLabelled types
<Divider type="text-line">or</Divider>
<Divider type="text">Earlier this week</Divider>
<Divider type="solid-text">Today</Divider>
<Divider type="section">Week 2 · Cell biology</Divider>Action
Figma's Icon Button, Icon Button Group, Text Button and Text Button Group become one action type: a line, your controls, a line.
<Divider type="action">
<Button size="sm" appearance="stroke" leadingIcon={<RiAddLine />}>Add section</Button>
</Divider>
<Divider type="action">
<Button size="sm" appearance="stroke" iconOnly aria-label="Add lesson"><RiAddLine /></Button>
</Divider>
<Divider type="action">
<ButtonGroup aria-label="Add content" size="xs">
<ButtonGroupItem leadingIcon={<RiAddLine />}>Lesson</ButtonGroupItem>
<ButtonGroupItem leadingIcon={<RiUpload2Line />}>Upload</ButtonGroupItem>
</ButtonGroup>
</Divider>Figma draws 32px and 28px controls. Use Button sm (36) or Button group sizes; the divider centres whatever you pass.
Orientation
<div className="toolbar"> {/* any flex row; the divider stretches to its height */}
<Button size="sm" appearance="ghost" iconOnly aria-label="Bold"><RiBold /></Button>
<Button size="sm" appearance="ghost" iconOnly aria-label="Italic"><RiItalic /></Button>
<Button size="sm" appearance="ghost" iconOnly aria-label="Underline"><RiUnderline /></Button>
<Divider orientation="vertical" />
<Button size="sm" appearance="ghost" iconOnly aria-label="Add link"><RiLinkM /></Button>
</div>vertical applies to line, line-spacing, text-line and action; the other types stay horizontal. It stretches to the height of a flex row, or set a height on the divider. Figma has no vertical variants; they were added for the brief (C39).
Dimensions
type | Figma Type | Box | Type style | Fill |
|---|---|---|---|---|
line | Line | 1px tall, full width | — | Stroke/Soft-200 |
line-spacing | Line Spacing | 4px band, 1px line centred (1.5 above and below) | — | Stroke/Soft-200 line |
text-line | Text & Line Divider | Line, label, line; 10 gap | Subheading/Small (14/20), uppercase | — |
text | Text Divider | Padding 4 / 8 | Label/Small (14/20) | — |
solid-text | Solid Text Divider | Padding 6 / 20, 6 gap | Subheading/2X Small (11/12), uppercase | Bg/Weak-50 |
action | Icon Button · Icon Button Group · Text Button · Text Button Group | Line, controls, line; 10 gap; controls keep their size | From the controls | — |
section | Seperator (sic) | Padding 12 / 100 (at most 8% of the viewport width), 40 gap | Label/Medium (16/28) | Bg/Soft-200 |
Values in px, from the component CSS, which follows Figma's geometry. Label text is Text/Sub-600 in every type. Vertical lines are 1px wide with a minimum of 8px each side of a label. The section band's narrow-screen inset is a code addition, pending a decision.
Composition examples
Two ways to add notes
A text-line divider separates two alternatives in the create-lesson flow.
A YouTube video, article or PDF.
<div className="stack">
<Button appearance="stroke" leadingIcon={<RiUpload2Line />}>Upload notes</Button>
<Divider type="text-line">or</Divider>
<Field label="Paste a link" hint="A YouTube video, article or PDF.">
<Input type="url" size="sm" />
</Field>
</div>Lessons grouped by week
A section band titles a group. When the label is a real heading for navigation, put the heading inside the divider so it appears in the page outline.
- Cell membranes
- Organelles
- Photosynthesis basics
<Divider type="section">Week 1 · What is a cell?</Divider>
<ul aria-label="Week 1 lessons">
<li>Cell membranes</li>
<li>Organelles</li>
</ul>
<Divider type="section">Week 2 · Cell biology</Divider>
<ul aria-label="Week 2 lessons">
<li>Photosynthesis basics</li>
</ul><Divider type="section">
<h3>Week 2 · Cell biology</h3> {/* reset the heading's margins and type in your styles */}
</Divider>Chat history by day
- Why do leaves change colour?
- Balancing chemical equations
<Divider type="solid-text">Today</Divider>
<ul aria-label="Today's chats">…</ul>
<Divider type="solid-text">Yesterday</Divider>
<ul aria-label="Yesterday's chats">…</ul>Load more lessons
An action divider holds a control between content. After loading, focus moves to the first new lesson.
- Photosynthesis basics
- Light reactions
<ul ref={listRef} aria-label="Lessons in Biology 101">{/* lessons */}</ul>
{hasMore ? (
<Divider type="action">
<Button size="sm" appearance="stroke" trailingIcon={<RiArrowDownSLine />} onClick={showMore}>
Show 2 more lessons
</Button>
</Divider>
) : (
<Divider type="text">All 4 lessons shown</Divider>
)}A thematic break people should hear
Most dividers are visual. When a break carries meaning, such as the end of the reading before a lesson's quiz, set decorative={false}. Screen readers announce a separator with the label as its name.
That covers the light reactions. Check what you remember.
1. Where in the cell does photosynthesis happen?
<p>That covers the light reactions. Check what you remember.</p>
<Divider type="text-line" decorative={false}>Quiz</Divider>
<p>1. Where in the cell does photosynthesis happen?</p>API reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
type | 'line' | 'line-spacing' | 'text-line' | 'text' | 'solid-text' | 'action' | 'section' | 'line' | Figma Type. See Dimensions for what each draws. |
orientation | 'horizontal' | 'vertical' | 'horizontal' | Vertical applies to line, line-spacing, text-line and action; ignored by the others. Stretch it in a flex row. |
decorative | boolean | true | true: lines are hidden from assistive technology and a label is read as plain text. false: role="separator", named by aria-label or a string label, with aria-orientation when vertical. Ignored by action. |
children | ReactNode | — | The label (Figma “Edit Text”) for the text types, or the controls for action. Ignored by line and line-spacing. |
ref | Ref<HTMLDivElement> | — | Forwarded to the root div. |
…rest | HTMLAttributes<HTMLDivElement> | — | Any native div attribute (className, aria-label, id…). className is merged. Attributes you pass override the computed ARIA, so don't pass aria-label={undefined} explicitly. |
Types exported: DividerProps, DividerType and DividerOrientation.
Styling hooks
The component renders .nu-divider with data-type and data-orientation, plus .nu-divider__line and .nu-divider__label inside. Use props rather than styling these. The supported override points are these component properties:
| Property | Default | Controls |
|---|---|---|
--nu-divider-color | --nu-stroke-soft-200 | Line colour |
--nu-divider-text-color | --nu-text-sub-600 | Label colour (Figma binds Soft-400; see Contrast) |
--nu-divider-gap | --nu-space-2-5 | Gap between lines and the label or controls |
--nu-divider-section-pad-inline | 100px | Section band inset, capped at 8vw |
Accessibility
Keyboard
| Key | Behaviour |
|---|---|
| Tab | Skips the divider; it is never focusable. In an action divider, Tab reaches your controls as usual. |
Screen readers
By default, lines are hidden and a label is read as plain text. With decorative={false}, the divider is a separator named by its label or aria-label. Action dividers never take the separator role, because a separator's content isn't operable.
Focus
No focus state; the divider isn't interactive. Controls in an action divider keep their own focus ring.
Contrast and colour
Figma binds labels to Text/Soft-400, 2.49:1 on white and 2.33:1 on Weak-50. Code uses Text/Sub-600 (6.69:1 and 6.24:1, D7, C12, C39). Lines are decorative. In forced colours, lines use CanvasText and bands get a border.
Touch and pointer
The divider has no target. In an action divider, the controls you pass set the target size; Button sm is 36 × 36.
You must: give a non-decorative line an aria-label; use a real heading, not a divider label, when the text is a section heading; keep labels short and in sentence case; label icon-only buttons in an action divider.
Figma mapping
| Figma property | Figma values | Code |
|---|---|---|
| Type | Line · Line Spacing · Text & Line Divider · Text Divider · Solid Text Divider · Seperator | type: line · line-spacing · text-line · text · solid-text · section |
| Type | Icon Button · Icon Button Group · Text Button · Text Button Group | type="action" with your Button or ButtonGroup as children |
| Edit Text | Default “OR” | children |
| Label colour | Text/Soft-400 | Text/Sub-600 (C39) |
| Not in Figma | Vertical, semantic separator | orientation, decorative |
Figma fixes pending (C39)
Figma's labels bind Text/Soft-400, which fails AA, and the Type value is spelled “Seperator”. Both are to be fixed in the D9 branch. Merging the four button types into action and adding vertical are code decisions for design to confirm.
Guidelines and related components
Use Content divider for
- Breaking long content, like lesson notes, into visual chunks.
- Separating alternatives: upload notes or paste a link.
- Grouping lists by week or day, or placing a “Show more” control between content.
Don't use Content divider for
- Separating items in a menu. Use the separator in Dropdown menu.
- Adding space. Use the layout gap (Spacing).
- Section headings that people navigate by. Use a real heading.
Do and don't
Common mistakes
- Typing labels in capitals (“OR”), so some screen readers may spell them out. Write “or”; the type uppercases it.
- Placing a horizontal divider directly in a flex row, where it shrinks to zero width. Give it a full-width parent.
- Setting
decorative={false}on every divider, which fills the reading order with separators. - Restyling the label to Soft-400 to match Figma; that fails contrast (C39).