Handoff: LabeledDivider
What and why
A horizontal rule with a pill label centered on it, to mark a point in a stream: a date, a jump in time or a state change such as "Zappy engaged". PDS v2 has no divider and nothing that labels a break in a stream, so event logs, runtime and edge logs, threads and agent timelines draw these by hand. The label can be swapped for any control with the action slot (2026-10-21; for example a "Show more" Button that unfolds content under the divider, the screen owns the control and the content), or optionally become a time selector: a MenuButton with a chevron that opens a menu to jump in time, with an optional last item that opens the PDS Datepicker in a Modal. Tones: neutral, agentic (AI gradient border, lines and bolt, with shimmer) and agentic-filled (discovery fill and border; two stylings under review). Figma: https://www.figma.com/design/AMGWJbraJoi2PKWnxo29Ah/PDS-Proposals?node-id=374-52, page Labeled Divider (4 stories, light only; captures of Storybook with library icons swapped in, sent 2026-10-20). Context: context.md.
Exploration and decisions
- Named
LabeledDividerbecause it is use-case neutral (StreamDivider,TimelineDividerandEventDividereach fit only some uses). If a plainDivideris added later, this can stay as the labeled form. - The time selector reuses the local
MenuButton(secondary, samesize) between the two lines instead of a new menu. The chevron means a time selector only, so there is no disclosure mode. The consumer owns the options and callbacks. - "Jump to a specific date" uses the PDS
Datepickerinside the PDSModal, becauseDatepickerhas no inline or controlled-open mode. The date takes two steps (click the field, then a day). - Icons are
prefixIconandsuffixIconprops, using the local Icon wrapper. - Sizes
xsands(default), named after the type tokens. A medium size was dropped as too large. - Tones:
accentwas removed.agentic-filled(the purple discovery fill) was removed 2026-10-21;agentic(the gradient) is the one agentic tone. Azappyicon on theagentictone is the plain foreground color (black); the gradient bolt was removed 2026-10-21. - Shimmer: the PDS shimmer band is an extra background layer on the agentic border and lines, using the package keyframes. Off for reduced motion. The label text and the selector's border do not shimmer.
- Type uses the semantic
pds-copy-s/pds-copy-xsclasses on the root, not font primitives.
Full list and reasons: decisions.md.
API
LabeledDivider (a div; extends div props):
| Prop | Type | Default | Purpose |
|---|---|---|---|
className |
string |
none | Additional class names. |
datePicker |
LabeledDividerDatePicker |
none | Adds a separator and a last menu item that opens a Datepicker in a Modal. Only used when menuItems is set. |
id |
string |
none | ID of the trigger button. Required for the selector (with menuItems). |
action |
ReactNode |
none | Swaps the label for any control, centered on the line (for example a "Show more" Button). The screen owns it, aria-expanded and the content it reveals. Ignores label, menuItems and the icons; the root is a group. |
label |
string |
none (required) | Text on the divider. Announced to screen readers on the static form. |
menuItems |
MenuButtonProps['menuItems'] |
none | Turns the label into a selector button with a chevron that opens this menu. Needs id. |
prefixIcon |
IconProps['iconName'] |
none | Icon before the label. |
size |
'xs' | 's' |
's' |
Text size, icon size and label padding; the selector's button takes the same size. |
suffixIcon |
IconProps['iconName'] |
none | Icon after the label (before the chevron on the selector). |
tone |
'neutral' | 'agentic' |
'neutral' |
agentic: AI gradient border, lines and shimmer. The selector always uses the gradient border when the tone is not neutral. |
LabeledDividerDatePicker: menuLabel (required, the menu item text), modalTitle (required), onChange(date) (required; the modal closes after a pick), pickerLabel (required, the field label), maxDate and value (optional).
Variants and states: sizes xs / s; tones neutral / agentic; static, selector or an action slot (a swapped-in control such as "Show more"); with or without icons; with or without the date picker. Stories: Default, With time selector, With action, Agentic, All sizes and variants. If menuItems is set without id, it renders the static form and ignores menuItems and datePicker.
Tokens used
--pds-animation-duration-ai-shimmer--pds-border-radius-button--pds-border-width-default--pds-color-border-separator--pds-color-foreground-default--pds-color-status-discovery-background--pds-color-status-discovery-border--pds-color-status-discovery-foreground--pds-color-surface-default--pds-gradient-ai-active--pds-gradient-ai-shimmer--pds-spacing-2xs--pds-spacing-3xs--pds-spacing-4xs--pds-spacing-m--pds-spacing-s--pds-spacing-xs
Also pds-copy-s / pds-copy-xs for type. --pds-spacing-l appears only in labeled-divider-story.css (story layout), so it is left out.
Impact
From impact.md: no existing PDS component is changed and no --pds-* token is redefined. One opt-in addition: .pds-labeled-divider__selector .pds-button (gap), which applies only inside the divider. The impact report lists LogsTableWithDivider as building on it. EventLogWithAgent also imports it in its stories (the report does not list it). Neither is marked ready.
Reused vs net-new
- Reused: local
MenuButton(the selector,secondary, agentic when the tone is not neutral), localIconwrapper, PDSModalandDatepicker(from the package), thepds-copy-*classes, PDS gradient, shimmer and status tokens. - Net-new:
.pds-labeled-divider(--agentic,--xs,__icon,__label,__line,__selector); all props; custom CSS variables--labeled-divider-label-background,-label-border,-label-color,-line-color,-padding-block,-padding-inline. No raw values kept. Details incustom.md.
Accessibility
- Static form:
role='separator'witharia-labelfromlabel; the visible pill and both lines arearia-hidden, so the label is announced once. - Selector form: not a separator. It is the MenuButton (a real button with its own menu semantics and keyboard handling); the lines are
aria-hidden. Needsid. - The date modal and Datepicker are the PDS components, with a title and a labelled field from the
datePickerprops. - The shimmer stops under
prefers-reduced-motion. - The a11y panel has not been run, and light and dark were not checked by eye in a session.
Decisions and open questions
- Is a modal the right container for the date picker, or a popover anchored to the divider? The Datepicker has no inline or controlled-open mode today, so the pick takes two steps.
- Is a vertical orientation needed for left-to-right timelines?
- Should the lead icon show on the selector in the neutral tone? It is supported; confirm it looks right.
- Check that the MenuButton height at each size matches the static pill.
- Silent fallback:
menuItemswithoutidrenders the static divider. Should the port warn or requireidby type? - Dependencies:
MenuButton(and through it Button, Icon, IconButton, Spinner) andIconare all marked ready.AgentAvatarappears in the dependency graph but is not imported by this component. Nothing it needs is unready.
Port notes
Would live in src/components/ (a dividers or layout category folder; generator npm run generate:component). Not yet matching v2: the local mergeClasses stand-in (use @libs/components/utils); the local MenuButton and Icon wrappers (use the ported ones); Modal and Datepicker already come from the package. Relies on the package pds-ai-shimmer-sweep keyframes being loaded. pds-copy-* is !important, so a rule on the same element cannot override size or weight.
Preview
npm run storybook, story Component Proposals / Labeled Divider. Figma: https://www.figma.com/design/AMGWJbraJoi2PKWnxo29Ah/PDS-Proposals?node-id=374-52, page Labeled Divider (4 stories, light only; captures of Storybook with library icons swapped in, sent 2026-10-20).