Skip to content

fix: complete preset safelist + component a11y/i18n from UI audit#15

Merged
phmatray merged 1 commit into
mainfrom
fix/ui-audit-safelist-a11y-i18n
Jun 10, 2026
Merged

fix: complete preset safelist + component a11y/i18n from UI audit#15
phmatray merged 1 commit into
mainfrom
fix/ui-audit-safelist-a11y-i18n

Conversation

@phmatray

Copy link
Copy Markdown
Owner

Summary

Findings from a multi-agent UI audit of a downstream consumer (Horizon Hub) traced back to the library. NuGet consumers cannot scan the kit's component .razor markup with Tailwind, so every class used inside the components is purged unless preset.css force-generates it — and the shipped safelist was incomplete, leaving components unstyled in consuming apps (Stat fully unstyled, Paper flat, chart legend swatches collapsed to zero size, dialog max-w-* sizing dead, FloatingLabel/Swap/Indicator/Hero/Rating/Countdown/Stack/table-zebra/table-sm all inert). Fixed once → every consumer benefits.

All changes are additive and backward-compatible; both DaisyBlazor.Components and DaisyBlazor.Charts build clean (0 warnings, 0 errors).

Changes (18 files)

Safelist (styles/preset.css + DaisyBlazor.Tailwind/preset.css, kept in sync) — add the structural & utility classes used literally in component markup: Stat/Stats, Paper shadows, card/collapse, table zebra/sm/pin, list-col-*, avatar-placeholder, indicator positions, swap, hero-overlay, rating-hidden, countdown, stack, floating-label, file-input-ghost, mockup, object-fit, modal max-w-*, theme *-content & base surfaces, padding utilities, and the DaisyBlazor.Charts legend/title primitives.

Accessibility (component code)

  • Card: role=button + tabindex=0 + Enter/Space keydown when OnClick is set (consumer attributes still win); unchanged when not clickable.
  • Th: scope="col" by default (consumer-supplied scope wins).
  • Tabs: role/aria-selected (+ aria-disabled); Medium now emits tabs-md.
  • Breadcrumbs: aria-current="page" on the leaf item.
  • Pagination: <nav> + labeled first/prev/next/last + aria-current on current page.
  • Fab/DockItem: AriaLabel parameter for accessible names.
  • DialogProvider: role=dialog + aria-modal + aria-label from title.
  • SnackbarProvider: toast container is an aria-live polite status region.

Localization (component code) — Autocomplete, DataGrid, DataGridPager, ProgressCircular, FeatureHomePage: hardcoded English turned into optional [Parameter]s defaulting to the current English text (localizable, no behavior change for existing consumers).

Notes / follow-ups

  • Tabs tabs-xl still needs a Size.ExtraLarge enum value before it can be wired.
  • Verified by building both projects locally (net10.0).

🤖 Generated with Claude Code

NuGet consumers cannot scan the kit's component .razor markup, so every
class used inside the components is purged unless preset.css force-generates
it. The shipped safelist was incomplete, leaving components unstyled in
consuming apps (Stat fully unstyled, Paper flat, chart legend swatches
collapsed, dialog max-w-* sizing dead, FloatingLabel/Swap/Indicator/Hero/
Rating/Countdown/Stack/table-zebra/table-sm all inert).

Safelist (styles/preset.css + DaisyBlazor.Tailwind/preset.css, kept in sync):
add the component structural & utility classes used literally in markup —
Stat/Stats, Paper shadows, card/collapse, table zebra/sm/pin, list-col-*,
avatar-placeholder, indicator positions, swap, hero-overlay, rating-hidden,
countdown, stack, floating-label, file-input-ghost, mockup, object-fit,
modal max-w-*, theme *-content & base surfaces, padding utilities, and the
DaisyBlazor.Charts legend/title primitives.

Accessibility (component code, additive & backward-compatible):
- Card: emit role=button, tabindex=0 and Enter/Space keydown when OnClick is
  set (consumer attributes still win); unchanged when not clickable.
- Th: scope="col" by default (consumer-supplied scope wins).
- Tabs: role/aria-selected (+ aria-disabled); Medium now emits tabs-md.
- Breadcrumbs: aria-current="page" on the leaf item.
- Pagination: <nav> + labeled first/prev/next/last + aria-current on current.
- Fab/DockItem: AriaLabel parameter for accessible names.
- DialogProvider: role=dialog + aria-modal + aria-label from title.
- SnackbarProvider: toast container is an aria-live polite status region.

Localization (component code): turn hardcoded English in Autocomplete,
DataGrid, DataGridPager, ProgressCircular and FeatureHomePage into optional
[Parameter]s defaulting to the current English text — localizable with no
behavior change for existing consumers.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@phmatray phmatray merged commit 80e7a67 into main Jun 10, 2026
1 check failed
@phmatray phmatray deleted the fix/ui-audit-safelist-a11y-i18n branch June 10, 2026 13:52
phmatray added a commit that referenced this pull request Jun 10, 2026
PR #15 branched off an older main and added aria-selected to the tab
button; commit c8783e9 had independently added it too, so the squash
merge left the attribute applied twice — a Razor duplicate-attribute
compile error that broke the 0.2.2 publish build. Keep the richer
WAI-ARIA version (id + aria-controls + panel linkage) and the unique
aria-disabled; drop the redundant second aria-selected.
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