TLDR
- New components DtTextList and DtTextListItem for bulleted, numbered, and custom-markered text lists.
- Replaces manual utility composition (
d-ls-reseton the container,d-lst-*repeated on every item,d-pis-*per nesting level) with validated props. - Semantic by default: renders a native
ulorolvia thetypeprop, withstart,reversed, and per-itemvaluenumbering controls. - The
markerslot accepts any content: Dialtone icons, emoji, or custom markup.markerTonecolors markers at the list or item level. - Nested lists get automatic marker progression (disc → circle → square; decimal → lower-alpha → lower-roman) with zero configuration.
- A new ESLint rule,
dialtone/deprecated-list-styling-classes, flags the deprecated utilities in Vue templates. - Component docs • Storybook
Why DtTextList Over CSS Utilities?
Building a text list previously meant composing utilities by hand, repeating the marker class on every single item:
Indentation is a spacing utility you pick by eye, inter-item rhythm is unmanaged, and nesting means another round of d-pis-* at every level. With DtTextList:
No repeated marker classes. No eyeballed indentation. The prop values are validated: pass marker="dots" and you get a console warning instead of silent failure. IDE autocomplete works, and the Dialtone MCP server returns the full prop API in one search for AI-assisted development.
Semantic by Default
DtTextList renders a real ul (the default) or a real ol, never a pile of styled div elements, so assistive technology announces "list, 3 items" the way it should. Ordered lists are one prop away:
Native numbering controls come along: start and reversed on the list, and :value on any item to jump the sequence.
Markers and Nesting
The marker prop covers the classic list-style-type values (disc, circle, square, decimal, lower-alpha, upper-alpha, lower-roman, upper-roman, none). You'll rarely need it: leave it unset and nested lists progress automatically (disc → circle → square for unordered; decimal → lower-alpha → lower-roman for ordered) just by nesting a dt-text-list inside a dt-text-list-item. Mixed types nest freely:
We recommend keeping nesting to three levels or fewer; beyond that, restructure with headings.
Custom Markers
The marker slot replaces the bullet with anything: a Dialtone icon, an emoji, or custom markup. Combined with per-item markerTone and item classes, a plain list becomes a rich status view. Every marker stays aligned with the first line of its text automatically, whatever the typography:
Custom markers are decorative by default and hidden from assistive technology. When a marker conveys state, like the icons above, include that state in the item's text.
Typography Inherits
DtTextList has zero typography opinion: it sets no font styles, so lists inherit from their context. Set type at the list level (or wrap a region in DtText) and the markers follow along; use the gap prop for inter-item rhythm on the familiar spacing scale.
What DtTextList Does NOT Do
- Typography: No font, size, or weight props. Use DtText.
- Container styling: No padding, surface, border, shadow, or sizing props. Use DtBox, or item classes as in the demo above.
- Layout: No direction or alignment. Use DtStack.
- Interactive rows: No hover, selection, or keyboard navigation. Use DtListItem.
- Term/definition pairs: Use DtDescriptionList.
- Rendered markdown: Prose content is styled by
d-prose.
These boundaries are intentional: DtTextList is a content primitive for static text lists, and the class attribute remains the escape hatch.
Migrating
The new ESLint rule dialtone/deprecated-list-styling-classes flags d-ls-reset, d-ls-none, and d-lst-* in Vue templates and points to DtTextList. The utility classes remain available for non-Vue markup and migration escape hatches.
See the full component documentation for all prop values, demos, and usage guidance.
