Skip to content

feat(streamdown): add hierarchical list bullet styles with depth trac…#489

Open
simon5057 wants to merge 2 commits intovercel:mainfrom
simon5057:fix/list-style
Open

feat(streamdown): add hierarchical list bullet styles with depth trac…#489
simon5057 wants to merge 2 commits intovercel:mainfrom
simon5057:fix/list-style

Conversation

@simon5057
Copy link
Copy Markdown

feat(streamdown): add hierarchical list bullet styles with depth tracking (#377)

Add listStyle prop to configure bullet style cycling for nested unordered lists. Defaults to hierarchical mode which cycles through disc → circle → square styles based on nesting depth.

Features:

  • Two style presets: flat (uniform disc, backward compatible) and hierarchical (disc/circle/square cycling)
  • data-depth attributes on all list elements for custom CSS targeting
  • Proper unordered depth tracking that skips ordered list nesting
  • Context-based depth propagation for accurate per-level styling

Description

Adds depth-aware bullet styling to nested unordered lists in the streamdown package. Previously all list items rendered with the same bullet style regardless of nesting level. Now the default "hierarchical" mode cycles through disc → circle → square as lists nest deeper, making it visually easy to distinguish list depth. Users who prefer uniform styling can opt into "flat" mode. All list elements receive a data-depth attribute for full custom CSS control.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Refactoring (no functional changes)

Related Issues

Fixes #
Closes #
Related to #

Changes Made

  • Added ListStylePreset type ("flat" | "hierarchical") and listStyle prop to StreamdownProps in index.tsx
  • Added listStyle to StreamdownContextType with default value "hierarchical"
  • Implemented ListContext in lib/components.tsx to track depth, ulDepth, and isUnordered through the component tree
  • Added LI_BULLET_STYLES preset map applying bullet classes (list-disc, list-[circle], list-[square]) on <li> elements based on ulDepth
  • Added data-depth attributes to all <ul>, <ol>, and <li> elements for custom CSS targeting
  • Added remend alias to vitest.config.ts for proper module resolution in tests

Testing

  • All existing tests pass
  • Added new tests for the changes
  • Manually tested the changes

Test Coverage

Created packages/streamdown/__tests__/list-style.test.tsx with 9 dedicated test cases:

Test Description
data-depth on <ul> Verifies root ul has data-depth="0", nested has data-depth="1"
data-depth on <ol> Verifies ordered list depth attributes
data-depth on <li> Verifies list items carry correct depth
flat mode Confirms all <li> use list-disc regardless of depth
hierarchical mode Confirms cycling: disc at depth 1, circle at depth 2, square at depth 3
no bullets in <ol> Verifies <li> inside <ol> receive no bullet class
no bullet class on <ul> Confirms bullet classes are on <li>, not parent <ul>
sibling lists reset Both sibling lists start at depth 0 independently
mixed ol/ul ulDepth only counts <ul> levels, skipping <ol> nesting

All 142 tests passing across 5 test files.

Checklist

  • My code follows the project's code style
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings or errors
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have created a changeset (pnpm changeset)

Changeset

  • I have created a changeset for these changes

Additional Notes

Custom styling via data-depth:

Users can target specific nesting depths directly in CSS without needing a new preset:

/* Style list items at specific depths */
li[data-streamdown="list-item"][data-depth="1"] {
  color: inherit;
}
li[data-streamdown="list-item"][data-depth="2"] {
  color: gray;
}
li[data-streamdown="list-item"][data-depth="3"] {
  color: darkgray;
}

ulDepth vs depth:

ulDepth counts only <ul> nesting levels and is used to determine the bullet style cycle. Total depth (which includes <ol>) is used for data-depth attributes. This means an <li> inside <ol> > <ul> correctly receives the depth-1 bullet style (disc), not depth-2, since the outer <ol> doesn't affect unordered bullet cycling.

…king(vercel#377)

Add `listStyle` prop to configure bullet style cycling for nested unordered lists. Defaults to hierarchical mode which cycles through disc → circle → square styles based on nesting depth.

Features:
- Two style presets: flat (uniform disc, backward compatible) and hierarchical (disc/circle/square cycling)
- `data-depth` attributes on all list elements for custom CSS targeting
- Proper unordered depth tracking that skips ordered list nesting
- Context-based depth propagation for accurate per-level styling
- Add listStyle to Styling Props TypeTable in configuration.mdx
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Mar 31, 2026

@simon5057 is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant