app-choice-link rendered a component host between the keuzelijst <ul>
and its <li>. This broke the axe list/listitem rule for assistive
technology. Five story suppressions named WP-11 as the fix, but WP-11
closed with no open ticket left to own the defect.
choice-link now uses selector: 'li[app-choice-link]', the same
attribute-host pattern as application-link. The host carries the
keuzelijst__list-item class; the template drops its own <li>.
Position: relative stays on .keuzelijst__link so the stretched-link
overlay still resolves against the card, not the host.
aanvraag-block needed no component change: it renders a CIBG melding,
never an <li>. Only its story wrapped it in a <ul>, which is what axe
rejected. The wrapper is removed, and the four non-Concept stories are
deleted — the component's template only renders for status Concept, so
they rendered nothing.
All five a11y: { disable: true } suppressions are gone, with no
replacement. atomic-design.mdx now records that both molecules are the
<li>, kept separate for the vendored CSS they bind, not for list
semantics.
npm run ci --full passes, axe included.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
131 lines
6.8 KiB
Markdown
131 lines
6.8 KiB
Markdown
# RD-37 — Five a11y suppressions name a ticket that closed
|
|
|
|
Status: done
|
|
Phase: 5 — fix the docs that describe this flow
|
|
|
|
## Why
|
|
|
|
Five stories carry `a11y: { disable: true }`. Four of the reasons say "WP-11 (CIBG markup
|
|
fidelity) reworks this markup". WP-11 is `Status: done`, and so is WP-13, the gap register that
|
|
WP-11 handed its remainder to. No open ticket owns the defect. The README rule — "no check
|
|
disabled without a reference to the ticket that removes it" — holds only in letter.
|
|
|
|
RD-30 archives `docs/project/backlog/`. This ticket runs first, so the archive move does not
|
|
rewrite five paths that must disappear.
|
|
|
|
The defect is shipped, not story-only. `app-choice-link` renders a component host between the
|
|
keuzelijst `<ul>` and its `<li>`. This breaks the axe `list`/`listitem` rule for assistive
|
|
technology. `display: contents` does not repair it.
|
|
|
|
## Read first
|
|
|
|
- `docs/project/readable-codebase/PLAN.md`, phase 5 item 0 (line 790).
|
|
- `libs/shared/src/ui/molecules/choice-link/choice-link.component.ts` — the defect.
|
|
- `libs/shared/src/ui/molecules/application-link/application-link.component.ts:18` — the
|
|
precedent. WP-11 made the host **be** the `<li>`. That component is axe-clean today.
|
|
- `libs/shared/docs/atomic-design.mdx:113` — the convergence table row that calls the split
|
|
deliberate.
|
|
|
|
## The question this ticket had to answer first
|
|
|
|
Does an `li[…]` attribute host still match the vendored CIBG keuzelijst CSS?
|
|
|
|
**Yes.** Verified against `public/cibg-huisstijl/css/huisstijl.css`. Every keuzelijst rule keys
|
|
off a bare class:
|
|
|
|
```
|
|
.keuzelijst__list{padding-left:0}
|
|
.keuzelijst__list-item{list-style:none;margin-bottom:1.5rem;position:relative}
|
|
.keuzelijst__link{…}
|
|
.keuzelijst__link:after{…} .keuzelijst__link:focus,.keuzelijst__link:hover{…}
|
|
```
|
|
|
|
There is no `ul > li` child combinator and no `li a` descendant chain. This is the difference
|
|
from the aanvragen pattern, whose vendored chain **is** `.dashboard-block.applications li a`.
|
|
An attribute host on the `<li>` therefore keeps every keuzelijst selector matching, as long as
|
|
the class `keuzelijst__list-item` moves to the host element.
|
|
|
|
## Decisions (pre-made, do not relitigate)
|
|
|
|
1. **`choice-link` becomes `selector: 'li[app-choice-link]'`.** The host carries the class
|
|
through `host: { class: 'keuzelijst__list-item' }`. The template drops its outer `<li>`.
|
|
`:host { display: contents }` goes away, because the host is now the list item.
|
|
2. **Keep `position: relative` on `.keuzelijst__link`.** The title is a `.stretched-link`. Its
|
|
`::after` overlay must resolve against the card, not against the `<li>`. Do not move that
|
|
rule to the host.
|
|
3. **`aanvraag-block` needs no component change. Its suppression reason is wrong.** The
|
|
component renders a CIBG melding (`app-alert`), never an `<li>`. Only the story's meta
|
|
`render` wraps it in `<ul class="keuzelijst__list">`, and that wrapper is what axe rejects.
|
|
Production agrees: `mijn-aanvragen.section.ts:44` renders the block for `concepten_()` only,
|
|
outside any list. Delete the wrapper from the meta render.
|
|
4. **Delete the four non-Concept stories in `aanvraag-block.stories.ts`.** The whole template
|
|
sits inside `@if (aanvraag().status.tag === 'Concept')`, so `InBehandelingAuto`,
|
|
`InBehandelingManual`, `Goedgekeurd` and `Afgewezen` render nothing at all. Keep `Concept`,
|
|
and give it the meta render. Submitted and resolved aanvragen render through
|
|
`application-link`, which has its own stories.
|
|
5. **Correct `atomic-design.mdx:113`.** After this ticket both molecules **are** the `<li>`.
|
|
The pair stays separate because they bind different vendored patterns, not because of list
|
|
semantics. Rewrite that half of the cell; keep the verdict.
|
|
6. **All five suppressions go.** No suppression, no replacement ticket. If `ci --full` still
|
|
reports a violation, stop and report it. Do not re-add a disable.
|
|
|
|
## Files
|
|
|
|
- `libs/shared/src/ui/molecules/choice-link/choice-link.component.ts` — host, class, template,
|
|
the header comment.
|
|
- `libs/shared/src/ui/molecules/task-list/task-list.component.ts:25` — the one production call
|
|
site: `<app-choice-link …/>` becomes `<li app-choice-link …></li>`.
|
|
- `libs/shared/src/ui/molecules/choice-link/choice-link.stories.ts` — call site + suppression.
|
|
- `libs/shared/src/ui/molecules/choice-list/choice-list.stories.ts` — call sites + suppression.
|
|
- `libs/shared/src/ui/molecules/task-list/task-list.stories.ts` — suppression.
|
|
- `apps/ssp/src/app/registratie/ui/dashboard/wat-moet-ik-regelen.section.stories.ts` —
|
|
suppression.
|
|
- `apps/ssp/src/app/registratie/ui/aanvraag-block/aanvraag-block.stories.ts` — wrapper, four
|
|
stories, suppression.
|
|
- `libs/shared/docs/atomic-design.mdx` — the convergence row.
|
|
|
|
## Steps
|
|
|
|
1. Convert `choice-link` to the `li[…]` host.
|
|
2. Update the one production call site and the two story templates. An attribute host needs a
|
|
closing tag: `<li app-choice-link …></li>`, not a self-closing element.
|
|
3. Fix `aanvraag-block.stories.ts` per decisions 3 and 4.
|
|
4. Delete all five `a11y: { disable: true }` blocks and their comments.
|
|
5. Correct the `atomic-design.mdx` row.
|
|
6. Run `npm run ci --full`.
|
|
|
|
## Acceptance criteria
|
|
|
|
- [x] No `a11y: { disable: true }` remains in `apps/` or `libs/`.
|
|
- [x] `grep -rn "WP-11" apps libs` returns nothing that points at the archived backlog.
|
|
- [x] `npm run ci --full` is green, axe included.
|
|
- [x] The keuzelijst still looks unchanged: chevron, hover accent, focus accent, and the
|
|
non-interactive `--static` row.
|
|
|
|
## Verification
|
|
|
|
1. `npm run ci --full`.
|
|
2. `npm run storybook` — Choice Link, Choice List, Task List and Wat Moet Ik Regelen run with
|
|
the a11y addon on. Check the three Choice Link stories by eye: `Navigatie`, `Actie` and
|
|
`NietInteractief` must keep their current appearance.
|
|
3. `npm start`, open `http://localhost:4200/dashboard` — the "Wat moet ik regelen" list renders
|
|
as before, and each row is still clickable over its whole surface.
|
|
|
|
## Out of scope
|
|
|
|
- `application-link` and `application-list`. Both are already axe-clean.
|
|
- The `--static` modifier and the CIBG-gap register. This ticket moves a host element; it adds
|
|
no new hand-rolled surface.
|
|
|
|
## Risks
|
|
|
|
1. **A self-closing attribute host silently renders nothing.** Angular needs
|
|
`<li app-choice-link></li>`. The build does not fail; the row disappears. Check the
|
|
dashboard by eye, per Verification step 3.
|
|
2. **`stretched-link` covers the wrong box.** If `position: relative` lands on the host instead
|
|
of on `.keuzelijst__link`, the whole `<li>` becomes the click target, including its
|
|
`margin-bottom`. Keep the rule where it is.
|
|
3. **The `choiceActions` slot must stay above the overlay.** It projects inside
|
|
`.keuzelijst__link` and relies on its own `position: relative; z-index: 2` at the call site.
|
|
The host move must not change the projection point.
|