Introducing DtTextList: Semantic Text Lists

Francis Rupert avatar
Francis Rupert

New component pair for bulleted, numbered, and custom-markered text lists. Replaces d-ls-*/d-lst-* utility composition with validated props, semantic ul/ol rendering, automatic nested-marker progression, and a marker slot that accepts icons, emoji, or any content.

TLDR

  • New components DtTextList and DtTextListItem for bulleted, numbered, and custom-markered text lists.
  • Replaces manual utility composition (d-ls-reset on the container, d-lst-* repeated on every item, d-pis-* per nesting level) with validated props.
  • Semantic by default: renders a native ul or ol via the type prop, with start, reversed, and per-item value numbering controls.
  • The marker slot accepts any content: Dialtone icons, emoji, or custom markup. markerTone colors 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 docsStorybook

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.

documentation last updated Wednesday, September 16, 2026