Update dependency @nldd/design-system to ^0.8.77 #212

Closed
robbertbos wants to merge 1 commit from renovate/nldd into main
Owner

This PR contains the following updates:

Package Change Age Confidence
@nldd/design-system ^0.8.70 → ^0.8.77 age confidence

Release Notes

MinBZK/storybook (@​nldd/design-system)

v0.8.77

Compare Source

  • fix(popover): clear a stale centering transform when the override goes (#​166) (81ee9e8), closes #​166
Fixed
  • nldd-popover — a popover that loses its centered (or edge) override at runtime no longer keeps the centering transform. The override branch cleared transform only while it was still being taken, so a responsive popover switching from centered to anchored on a breakpoint change kept translate(-50%, …) on top of Floating UI's coordinates and landed half its width off its anchor, partly off screen. Floating UI positions purely through left/top, so the transform is now cleared whenever no override applies.

v0.8.76

Compare Source

Fixed
  • nldd-menu — a button that opens a menu now carries aria-haspopup from the first render instead of from its first open. aria-haspopup describes the trigger ("this button opens a menu"), not a state, and deferring it left a screen reader tabbing a row of identical "more" buttons hearing plain "button" — precisely when the type matters, since nothing has been opened yet. Because popup-type also decides whether aria-expanded is rendered at all, a button without expandable had neither attribute until first use. nldd-popover already worked this way; the two now agree. Setting popup-type yourself still wins, so no markup has to change.

v0.8.75

Compare Source

  • feat: font-free stylesheet entry, month picker, markdown code blocks and open-source docs (#​164) (263ffd6), closes #​164
Highlights
  • Month and year each have their own menu. The heading showed both with one chevron and opened a list of years only. Changing the month went by arrow, one step at a time, so a month on the other side of the year took up to six clicks. Both menus offer only what min and max allow. "Vandaag" moved out of the heading to the bottom left, which is what makes room for a month written out in full. The calendar in nldd-date-field opens under the input as well, instead of running off to the right of it (#​156).
  • Open-source documentation expanded. A code of conduct, a route for reporting vulnerabilities, a support page, a description of who decides what, and a publiccode.yml for the catalogue on developer.overheid.nl. The contributing guide grew from a page of changelog conventions into an actual guide (#​149).
  • Host styling now survives a consuming app's CSS reset. A universal rule like * { margin: 0; padding: 0; border: 0 } in a consuming app silently beat every normal :host declaration (CSS Scoping cascade order, #​160), stripping padding, dividers, and spacing from components that styled their shadow host. Banner, container, menu groups and dividers, table rows, cells, and interactive list rows now keep their layout under any reset, including Tailwind Preflight. Styling remains a CSS-variables affair — direct element styling such as nldd-banner { padding: … } was never a supported API and now consistently has no effect.
  • New icons. viewfinder-line (alias scan) is the existing viewfinder with a scan line through it, for scanning a document or a code. display and paintbrush landed in the same batch.
Added
  • Icons — viewfinder-line (alias scan), display, paintbrush.
  • nldd-card — a background attribute: base (default) or tinted, for a card that has to lift off a base surface. Customize with --components-card-tinted-*.
  • @nldd/design-system/styles/system-font — the same stylesheet as /styles, without the @font-face rules. Both family stacks end in a system font, so they fall through on their own; nothing needs overriding. For products that may not use the Rijksoverheid house fonts (see NOTICES.md).
  • @nldd/design-system/styles/variables — only the CSS custom properties, for a build that composes the stylesheets itself.
  • @nldd/design-system/breakpoints — the breakpoints for matchMedia and layout logic, previously behind /tokens.
Changed
  • nldd-date-picker — the heading read "September 2026" with a chevron, promising both, and opened a list of years only (#​156). Month and year are now each their own button with their own menu, so a month on the other side of the year is two clicks instead of up to six on an arrow. "Vandaag" moves out of the heading to the bottom left, where the stacked layout already had it; that is what makes room for a month written out in full. The heading no longer wraps between month and year. The month and year buttons stand as tall as the paging controls beside them (32px, 44px stacked) instead of bare 22px text, which also satisfies the WCAG 2.5.8 target size. Both menus offer only what min and max allow, and a part with a single reachable value drops its chevron and its menu rather than opening to confirm what you already see.
  • nldd-date-picker — the day numbers carry medium weight. Weight was doing no work in the calendar (today is a ring, selected is a fill), so it was free to separate the dates from the chrome around them: the weekday headers and the week numbers now recede together (#​156).
  • nldd-title — a slotted heading is capped at a 40ch measure and balances its lines, so a title on a wide section no longer runs the full width with a lonely last word.
  • nldd-list-item — a row that opens with an icon now starts its divider at the first text or title cell, so the line aligns with the words instead of the icon. Consumers no longer need a divider-start marker for this; an explicit marker still wins, and putting one on the icon cell restores the full-width line.
  • Document typography — the stylesheet now gives the body the document font and content color as soon as an nldd-app-view is on the page. Apps no longer need their own body { font: … }. The rule sits in @layer reset, so any consumer rule beats it without effort; a page without an app-view is untouched.
Breaking
  • @nldd/design-system/tokens is gone. It only ever re-exported breakpoints, so import from @nldd/design-system/breakpoints instead. Same values, same names.
  • The four --primitives-font-family-*-fallback variables are gone. Nothing read them, so overriding one to drop RijksSans changed nothing while looking like the switch you were after. To use a different font, override --primitives-font-family-sans-serif and --primitives-font-family-monospace — or import /styles/system-font and skip the @font-face rules entirely.
Fixed
  • nldd-date-field — the calendar hangs off the trigger, which sits at the end of the field, and opened rightward from there: on a 192px field it ran 302px past the field's right edge and barely overlapped the input it belonged to. It now opens leftward, landing under the input; against the left edge of the screen Floating UI falls back to the old direction on its own (#​156).
  • nldd-rich-text — a markdown renderer emits a fenced code block as <pre><code>, and the tinted chip meant for inline code painted once per rendered line, so a three-line block showed three separate boxes (#​158). The frame now sits on the pre, where the block is, and the code inside hands the chip back. It carries the same inset ring as nldd-box and nldd-code-viewer, so the block stays readable on a tinted surface instead of dissolving into it.
  • nldd-rich-text — a pre had no overflow-x, so a single long code line escaped the element and stretched every ancestor with it. In a narrow card that read as rich-text ignoring the card width. Long lines now scroll inside the block, as a table already did.
  • nldd-date-picker — activating a paging arrow or "Vandaag" pulled focus into the day grid, so paging twice meant finding the arrow again. Focus now stays on the control that was activated; only the roving tabindex moves along, so tabbing into the grid still lands on the equivalent day.
  • nldd-date-field and nldd-password-field — the embedded button's focus ring carries a 6px halo meant to land exactly on the field's border, but the field's overflow: hidden clipped it at the padding box, leaving the border to cut through the ring. The clip is gone: nothing in either field can escape without it (the input clips its own text, and the autofill background is overridden inside the input), so the ring now paints over the field the way it does over any other neighbour.
  • nldd-popover — after any mouse interaction, tabbing through the popover showed no focus rings. The popover intercepted every Tab and moved focus itself (a Safari workaround), but a script-moved focus only inherits the ring state of the element it left, where a browser-moved one gets a ring unconditionally — so one ringless start poisoned every stop after it. The popover now intercepts only the hop off the container (the one Safari cannot make) and the boundary that closes it; every Tab in between is the browser's. That entry hop also serves a click on the popover's dead chrome: Tab then starts at the top of the popover instead of resuming from wherever focus happened to be.
  • nldd-tooltip — activating the trigger now dismisses the tooltip. It sat in the top layer above the popover that very click had opened, because manual popovers paint over auto ones that enter later.
  • nldd-collection — the previous/next arrows in layout="horizontal-scroll" stepped by a fixed distance, so from the end of the strip (never a whole number of items) every item stayed clipped. The arrows now snap to the nearest item edge.
  • nldd-collection — reaching an end with the keyboard disabled the arrow you were standing on, and a disabled control cannot hold focus, so focus fell to the body and the next Tab restarted at the top of the page. Focus now moves to the sibling arrow.
  • nldd-container — layout="lanes" and layout="columns" ignored sm-gap, md-gap and lg-gap and always used the base gap. Every layout now reads one resolved gap, so the per-breakpoint values apply to multicol too.
  • nldd-banner — the visual frame (background, inset border, corner radius, padding, grid) moved from the host to a wrapper inside the shadow root, out of reach of document CSS. Use --components-banner-* to customize.
  • nldd-container — the padding and the query container moved to a wrapper inside the shadow root (host > .container > .container__inner), out of reach of document CSS; size queries still measure the same padded interior width.
  • nldd-menu-group and nldd-menu-divider — dividers, spacing, and padding moved to elements inside the shadow root, out of reach of document CSS; their flow-root hosts keep that spacing interior, so menus keep their grouping and rhythm under a reset.
  • nldd-table-row, the cell family, and interactive nldd-list-item rows — row dividers, row padding (--context-cell-padding-block), and the widened inset of interactive rows shield their host declarations, since subgrid participation and negative margins cannot move into the shadow tree.

v0.8.74

Compare Source

v0.8.73

Compare Source

  • feat: 32 nieuwe iconen, icon-gallery met statusfilter en fine-tuning (#​163) (0425e4d), closes #​163
Highlights
  • 37 new icons. Sound and image (microphone, speaker and its volume steps, photo-camera, video-camera, photo-on-photo-angled for a gallery, photo-stack), maps and wayfinding (map, map-pin and its badge variants, map-pin-oval for your current location, signpost for directions), a fuller file and folder family (file-badge-*, file-on-file, folder-open, folder-badge-plus), arrow-clockwise for refresh, a pair of expand and collapse arrows, clipboard-pencil for a form, hand-thumbs-up and hand-thumbs-down for a like and a dislike, person-badge-minus, link-badge-lock for a secure link, slider-horizontal-3 for local settings, text-format-size, and square-grid-2x2 with a pencil variant. The full list is under Added.
  • 11 icons are redrawn. The file and folder family (file, file-text and its badge and pencil variants, file-text-on-file-text, folder), the stack icons (rectangle-stack, rectangle-stack-text, rectangle-stack-chevron-left-forward-slash-chevron-right) and house-apartment-building got new artwork, so the set draws with one pen again now that it has grown.
Added
  • Icons — apartment-building-2 (aliases buildings and offices), arrow-clockwise (aliases refresh and reload), arrow-down-left-arrow-up-right (aliases expand and full-screen), arrow-up-right-arrow-down-left (aliases collapse and exit-full-screen), clipboard-pencil (alias form), file-badge-arrow-down (alias download-document), file-badge-arrow-up (alias upload-document), file-badge-minus (alias remove-document), file-badge-plus (alias new-document), file-on-file (alias documents), folder-badge-plus (alias new-folder), folder-open, hand-thumbs-up (alias like), hand-thumbs-down (alias dislike), link-badge-lock (aliases secure-link and secure-url), map, map-pin (alias location), map-pin-badge-plus (alias add-location), map-pin-badge-minus (alias remove-location), map-pin-oval (alias current-location), microphone (alias microphone-on), microphone-slash (alias microphone-off), person-badge-minus (alias remove-user), photo-camera (alias camera), photo-on-photo-angled (alias gallery), photo-stack (aliases image-stack and images), signpost (alias directions), slider-horizontal-3 (alias local-settings), speaker, speaker-slash (alias mute), speaker-volume-low (alias low-volume), speaker-volume-medium (alias medium-volume), speaker-volume-high (alias high-volume), square-grid-2x2, square-grid-2x2-pencil, text-format-size and video-camera.
Changed
  • Step indicator and timeline track cell, fine-tuned. The current step's fill is one step lighter, the number in the marker is one weight heavier (medium), and a minor dot on the plain track grew from 8px to 10px (a minor step marker stays 12px).
  • The icon gallery shows what changed. The tiles of the latest icon batch carry a "Nieuw" or "Bijgewerkt" tag, and a segmented control next to the search field filters on "Alles", "Nieuw" and "Bijgewerkt".
  • The refresh and reload aliases point at the new arrow-clockwise. They sat on arrow-2-counter-clockwise, which keeps sync — two arrows chasing each other read as synchronization, one clockwise arrow as a refresh.
  • file-text-pencil gains the edit-text-document alias, next to new-text-document and add-text-document on its check-plus sibling.
  • The dismiss icons gain close aliases: close for dismiss, and close-circle, close-circle-filled, close-small and close-extra-small for their variants.
  • rectangle-stack is redrawn and gains the library alias, next to the existing stack.
  • stack-code is now the alias of rectangle-stack-chevron-left-forward-slash-chevron-right. The icon is renamed (and redrawn) after the shape-first pattern of chevron-left-forward-slash-chevron-right; the old name keeps working as its functional alias.
  • The documents alias points at file-on-file. It sat on the icon now called file-text-on-file-text, which keeps text-documents — the plain pair is the generic plural, the way document already sat on plain file.
Breaking
  • Three icons renamed, because -stack is reserved for 3 or more and these draw 2: file-text-stack is now file-text-on-file-text (with new artwork), folder-stack is now folder-on-folder, and tag-stack is now tag-on-tag. The old names are gone. The aliases text-documents, directories, tags and labels moved along and keep working.
  • stack-text is now rectangle-stack-text (with new artwork), naming the shape it draws the way rectangle-stack already does.
  • house-and-appartment-building is now house-apartment-building (with new artwork) — the spelling fixed to match apartment-building, and the "and" dropped from the compound.
  • square-and-arrow-down is now square-arrow-down, dropping the "and" the way square-arrow-up and square-arrow-right-top already read. The aliases save and import moved along and keep working.
  • The media-transport icons carry a media- prefix: backward, forward and their -filled, -end, -end-filled, -frame and -frame-filled variants are now media-backward, media-forward and so on (12 renames). The bare names were ambiguous — "forward" reads as navigation more often than as media transport — and the icon forward was unreachable outright, shadowed by the alias forward → chevron-right (aliases win on resolution). That alias stays, as the counterpart of back → chevron-left. play, pause, stop and play-pause keep their names: they collide with nothing and are clear as they are.

v0.8.72

Compare Source

  • fix(timeline-track-cell): laat het spoor over de rijgrens doorlopen (#​162) (950d6c1), closes #​162
Fixed
  • The timeline track broke at every row. An nldd-list-item reserves a divider's worth of space below itself, and the lines of nldd-timeline-track-cell stopped at the cell's edge — leaving a hairline gap between one row's track and the next. The lines that run on downward now bridge that band.

v0.8.71

Compare Source

Highlights
  • New nldd-step-indicator for a process of several steps. A row of markers carrying a number (or a check mark once a step is done), a label below each and a track in between. current on the parent derives every step's status (past, current, future); a step can override it. A finished step is filled with a check mark, the current one is an accent outline on a light accent field around its number, and what is still to come is a quiet grey field. With href or button a step becomes a control, so you can page back — also in a flow without a URL per step. Below the sm breakpoint (measured on the container) it collapses to one line of text plus a segmented bar, with the full list of steps still in the DOM for assistive technology. Horizontal only: steps below one another are a list of nldd-timeline-track-cell.
  • A list can be a tree. nldd-list type="tree" makes the list a role="tree" of treeitem rows; a branch's child rows go in that row's children slot, which the item renders as a role="group" and hides while expanded is off. The nesting is the hierarchy, so level, position and set size are derived rather than authored. Disclosure works two ways: a chevron of its own (nldd-list-item-action[disclosure]) or the row itself as the control (button plus expanded), where an nldd-icon-cell marked disclosure turns along. Indentation stays the consumer's: repeat a spacer-cell per level. A tree brings its own keyboard, see below.
  • nldd-timeline-track-cell is now the vertical counterpart of the step indicator. With variant="step" the marker carries a number or icon and you have a step list below one another; by default it stays the bare track for a timeline of events.
  • A tree comes with its own keyboard. type="tree" is a composite widget, so it no longer waits for arrow-navigation: up and down move between the rows in the order they appear on screen (the rows of an open branch included), Home and End jump to the ends, Right opens a closed branch and steps into an open one, Left closes an open branch and steps out of a leaf, and Enter and Space open and close from the row itself. Opening and closing runs through the row's own disclosure control, so expanded keeps being written in one place — your handler; a row that is a link is never activated that way. The tree is one tab stop: focus lands on the row (that is where treeitem sits, so the row gets announced rather than a button inside it), wearing the system's own focus ring around the row rather than the browser's outline around the whole open branch, and Tab then walks the controls of that row, a chevron beside a checkbox included. Deliberately between two patterns: a row with several controls is strictly a treegrid, and we keep the tree semantics while borrowing Tab-within-the-row from the grid.
  • New icons. bug, square, square-1 (alias primary), triangle-square-circle (alias categories), book-badge-plus (alias new-book), tag-stack (aliases tags and labels, for a set of labels where tag is one) and person-text-rectangle (alias contact-card), plus the aliases add-text-document for file-text-badge-check-plus, announcement for megaphone and company for apartment-building. The alias category for tag is gone: a label is not a category, and beside the new categories (triangle-square-circle) the two read as the same thing. Use tag or label.
  • Surfaces carry their boundary with a border, from one family of tokens. The border colour of base and tinted surfaces is the divider colour (one step lighter in light mode than before), its thickness is --semantics-surfaces-border-width and the corner radius --semantics-surfaces-corner-radius (10px). Cards, boxes, boxed lists, tables, the code viewer and the sidebar box all follow from that one place, and nldd-card loses its drop shadow to become an ordinary base surface. In dark mode the card used to be a lighter field that happened to stand out; now the border carries it in both schemes.
Breaking
  • nldd-list-item — the start and end slots are gone. Put the cells that sat there (avatars, spacers, icons) in the row itself, in the same place. The divider spans the full content width by default; if you used the slots to start it later or stop it earlier (after an avatar, say), mark the cell where it should begin or end with divider-start or divider-end. Without divider-start it starts at the front, without divider-end it runs to the end. The children slot for nested rows stays. The hover and selection fill of an interactive row is now genuinely clickable across the full painted width.
  • nldd-list-item-action — a segmented action: an action covering part of the row, as opposed to the row-wide action nldd-list-item renders itself with href or button. Segmented actions now own a fixed inline padding and are at least as wide as the row's control size (md 44px, sm 32px), so the hit area is a square at minimum. Remove spacer cells you added inside one for room or hit area — the action handles that itself now, and leaving them in doubles the space. Icon-only actions (a chevron in a tree) get slightly wider. An action at a row edge shifts 8px towards that edge, so its outer edge lands exactly where a row-wide action's hit area begins and its contents sit on the same grid as the text of an ordinary row. It shifts, it does not grow: the width stays the control size. If you reserve the chevron zone on leaf rows in a tree, watch rows without an indent spacer in front — there a branch row's action shifts along and the zone sits 8px further out. An action mid-row is unaffected.
  • nldd-timeline-track-cell — the attributes have new names. step is status (same values, the same vocabulary as nldd-step-indicator-item), child is position (it is about the place in the sequence, not a DOM relation), and the size is no longer picked in pixels but through variant: dot (default, a bare track) or step (a 24px marker with a number or icon in it).
  • The serif tokens are gone. --primitives-font-family-serif and -serif-fallback pointed at RijksoverheidSerif, a font the system does not ship and no component used. If you referenced them, set your own stack.
  • Three corner-radius tokens are gone, because all three said the same thing in three places: --components-box-corner-radius, --components-list-corner-radius and --components-sidebar-section-sidebar-box-corner-radius. Every surface now takes its radius from --semantics-surfaces-corner-radius; that is the only place to round them off, or square them off. New alongside it is --semantics-surfaces-border-width, so border and divider move together in thickness as well. Both sit at family level, because base and tinted share them (the border colours stay per variant).
  • Two icons renamed. rectangle-chevron-left-forward-slash-chevron-right is now chevron-left-forward-slash-chevron-right-rectangle, so the shape it sits in comes last, the way the other names read. And square-corner-4 is now viewfinder — four loose corners describe the drawing, not what it does. Their aliases code-block and fit-to-view are unchanged and remain the names to reach for.
  • The icon alias category is gone. It pointed at tag, and next to the new categories alias (which points at triangle-square-circle) the pair suggested two views of one thing while they are different concepts. icon="category" no longer resolves; use tag or label.
  • nldd-radio-button-field._commitFormValue() is commitFormValue(). The method was meant for nldd-radio-button-group (which calls it on the siblings it unchecks) but was public; it now comes from the shared mixin and therefore drops the underscore.
  • accessible-labelled-by is now accessible-labeled-by on nldd-segmented-control, nldd-radio-button-group and nldd-toggle-button-group; the property is accessibleLabeledBy. The system writes US English, also where the HTML spec does not: the forwarded aria-labelledby keeps its own spelling, because that one belongs to the spec.
  • Translation keys for aria labels now end in -label. -label-text said it twice, since the type already says it is a label. Renamed: list.items-label-text → list.items-accessible-label, list.navigation-label-text → list.navigation-accessible-label, list.search-placeholder-text → list.search-placeholder-label, drag-handle-cell.label-text → drag-handle-cell.accessible-label, progress-bar.label-text and progress-circle.label-text → accessible-label, their loading-text → loading-label, activity-indicator.loading-text → loading-label, badge.notification-text → notification-label, token-field.removable-hint → removable-lowercase-label, and opens-in-new-tab-text → opens-in-new-tab-label on nldd-list-item, nldd-card, nldd-link, nldd-avatar, nldd-button and nldd-icon-button. pagination.accessibility-label is now pagination.accessible-label, as everywhere else. The texts themselves are unchanged; if you override a key through translations, update the name.
  • Two translation keys turned US English: components.list.reorder-cancelled-text and components.document-tab-bar.reorder-cancelled-text are now reorder-canceled-text. Update the key if you override it through translations; the Dutch default text is unchanged.
  • Every token that feeds a border-width is now named that way. --semantics-input-fields-border-thickness, --components-checkbox-border-thickness, --components-radio-button-border-thickness, --components-radio-button-is-selected-inner-shape-border-thickness, --components-switch-border-thickness, --components-switch-thumb-border-thickness and --components-keyboard-shortcut-border-thickness end in -border-width. The value comes from --primitives-border-width-* and goes into a border-width, so renaming it halfway only bought a word to remember. A line that is not a border keeps thickness: --semantics-dividers-thickness feeds a height, and --semantics-dividers-width would read as how wide a divider is.
  • The internal context variable --context-list-item-min-size is now --context-list-item-size. Only relevant if you hooked into it yourself.
Added
  • nldd-step-indicator and nldd-step-indicator-item (status & feedback) — new. On the parent: current (1-based), accessible-label and translations. On a step: text, icon, status (overrides what the parent derives), href or button.
  • nldd-list — type="tree", plus the children slot and expanded on nldd-list-item for branch rows. disclosure on an nldd-icon-cell turns the chevron along with expanded.
  • divider-start and divider-end on cells — let the row divider begin or end at a cell (after the avatar, say). Several markers together span from the first start to the last end.
  • nldd-timeline-track-cell — variant (dot / step), minor for a row that belongs under the one above it (a smaller marker in the same lane, so the track runs straight and nothing indents), text and icon for what the marker carries, and direction="up" for a timeline with the newest at the top.
  • nldd-avatar — href, target, rel, button and accessible-label: the disc itself becomes the control, so hit area and focus ring follow the round shape instead of a square overlay, and the initials get no underline. The name comes from accessible-label, or else from name; href wins over button, as with nldd-card.
  • nldd-button — max-width: caps the button at a CSS length, also alongside width="full" (follow the container, but no wider than this). A label that doesn't fit is truncated with an ellipsis, because a cap the content ignores isn't a cap.
  • nldd-window — no-light-dismiss: a click beside the window no longer closes it, while Escape and the dismiss button keep working. For windows where dismissing by accident costs work, such as a wizard or a filled-in form.
  • nldd-icon — size="full" names the existing behaviour (fill whatever sizes you) and size="inherit" makes the icon follow the surrounding text (1em), for an icon set in a sentence. Reach for the latter rather than your own nldd-icon { width: 1em } rule: such a rule wins over the component and also shrinks the icons a cell or button was already sizing correctly.
  • nldd-date-picker — width: full or a CSS length, next to the intrinsic seven-cell width.
  • nldd-menu — the anchorElement property positions the menu against an element without turning it into a toggle. For a menu you open yourself (a type-ahead under a text field), where the anchor attribute would swallow the click on the anchor.
Changed
  • nldd-card has no drop shadow and is an ordinary base surface. Field, border and corner radius come from the same --semantics-surfaces-base-* family as a boxed nldd-list or nldd-table. --components-card-box-shadow is none; set it back if you want the shadow.
  • The boundary between two rows is real space now, not paint a row withholds. An nldd-list-item has a 1px bottom margin and the divider hangs in it, so a hover or selection fill runs to the row's own edge. That retires the internal context variable --context-list-item-boundary-inset, which existed only so a slotted nldd-list-item-action could withhold the same pixel. A list grows 1px per row; if you measure row positions yourself, count the margin in. While dragging, the divider of the lifted row and of its drag clone is hidden.
  • Boxed lists: fills sit 4px clear of the frame, and the frame no longer clips. The rows sit far enough inside the frame that their fills never reach its corners, so the overflow: hidden that rounded them off against it could go — a focus ring inside a box now paints outward like every other control instead of being cut off 4px away. The row fill follows suit and rounds off a step more tightly (6px), concentric with the 10px frame around it. Content and dividers do not move; no action needed.
  • A row can be its own disclosure control and still turn its chevron. Mark the chevron's nldd-icon-cell with disclosure and nldd-list-item rotates it with expanded, the same affordance nldd-list-item-action[disclosure] already gave. Until now a tree had to choose: a chevron that turns (only the chevron clickable) or a fully clickable row (a chevron that never moves).
  • nldd-checkbox-field and nldd-radio-button-field are form-associated. They submit value under name, exactly like nldd-checkbox and nldd-radio-button; previously the inner control sat unreachable in the field's shadow root and the value never made it into the form. nldd-radio-button-group keeps exactly one value in the form while the change event is still propagating, so a consumer serialising in its own listener (htmx, new FormData(form)) never sees two. Both support form.reset() and reflect name.
  • All eighteen form-associated inputs share one FormAssociated mixin. formAssociated, the ElementInternals, formDisabledCallback and the moment of committing sat in eighteen files, each with its own _syncFormValue. A component now supplies only what is its own: formValue(), and formState() where the value alone cannot rebuild the control. The timing rule lives in one place: the value is committed on every render and has to be committed again from the handler itself with commitFormValue(), because a render is a task later than the event. Nothing changes on the outside, except that internals, formValue() and commitFormValue() now exist on each of those components.
  • nldd-table hands its row padding to the cells, through the same --context-cell-padding-block the list uses. The inline padding stays on the row, so the full-bleed divider does not move.
  • nldd-code-viewer and the sidebar box follow the surface tokens. Both took a hard-coded 1px border, and the viewer its own corner-radius-lg; border width and corner radius now come from --semantics-surfaces-border-width and --semantics-surfaces-corner-radius, so they move along with every other surface instead of drifting on their own.
  • nldd-box takes its border width from a token. The 1px was hard-coded in the box-shadow; there is now --components-box-border-width (defaulting to --semantics-surfaces-border-width), and the border is painted from one composed variable, as in nldd-card.
  • nldd-collection decides its gap on container width, not only on the viewport, and grid children get min-width: 0. One long unbreakable string in a card used to stretch its whole column, and every consumer had to catch that themselves.
  • nldd-avatar: the initials are a step smaller and lighter, and optically centred. Capitals do not use the space below the baseline, so centring on the em box left them sitting visibly high.
  • nldd-form-field: more room above help and error text, equal to the space between label and control.
  • The monospace stack has real fallbacks. Behind JetBrains Mono stood the generic monospace alone, which on many systems is Courier New: thinner, narrower and with a smaller x-height, so code looked entirely different while the web font had not loaded (or never arrived). ui-monospace, Menlo, Consolas and DejaVu Sans Mono now come first.
  • nldd-top-navigation-bar: wordmark, title space and focus ring. The wordmark text wraps within the logo instead of running on as a sentence, the website title next to the menu bar gets the same padding on its right as the menu items (so the hover state no longer bumps into it), and the focus ring of the logo link sits around the ribbon instead of the whole block.
Fixed
  • The component reference was missing eight components. nldd-menu, nldd-menu-item, nldd-menu-divider, nldd-menu-group, nldd-breadcrumbs-item, nldd-button-bar-divider, nldd-page-footer-legal-bar and -legal-bar-item did not appear in skills/nldd/reference.md: their documentation sits above their own class rather than at the top of the file, and the generator only read the first block. It now reads every block that names its element with @element.
  • A label of nldd-form-field slid over a sticky header. The field's header deliberately sits above its own input (z-index: 1), but without a stacking context of its own that z-index competed in the page's nearest context and beat the sticky title bar the field scrolls under. The field now isolates itself.
  • nldd-form let hidden fields take up space. The gap hung as margin-top on every following child, so an <input type="hidden"> (formset bookkeeping, framework plumbing) pushed the first visible field down. The gap now hangs below the preceding child, and hidden children render no box.
  • An nldd-button in a flex or grid parent had an invisible full-width box. The host stretched with the column while the button inside stayed content-sized, so the element was several times wider than what you see — surprising when you inspect it, and it swallows clicks that look like they land beside the button. The host now has a definite width and only stretches with width="full".
  • A focused nldd-card lost the halo around its focus ring. The ring was drawn on the card itself, combining the card's own box-shadow token with the ring's in one declaration — and that token is none, which cannot sit in a comma-separated shadow list, so the whole declaration was dropped. The outline still showed, the white halo that separates it from the background did not. The ring now sits in its own layer beside the card, where the card's overflow can't clip it either.
  • nldd-card with href showed the hand cursor. The overlay link now follows --semantics-controls-link-cursor, like nldd-link and an nldd-list-item with href.
  • nldd-collection used the small gap at large widths when it sat inside a container-query ancestor (a card, a page, a window, a sheet). The viewport rule was right, its container-query twin read the sm token.
  • nldd-window emitted close for a close from its own contents. A nested overlay (the popover of a date field, say) fires a composed, bubbling close that reaches the window's own listener: consumers tore the window down while it stayed open, and the real close was then swallowed. nldd-sheet already guarded against this; the window now does too.
  • A radio nldd-toggle-button-group briefly had two values in the form. Deselecting the other buttons waited for their next render, so a consumer serialising the form in its own change listener (htmx, new FormData(form)) saw both the old and the new value. The group now commits the deselected buttons from the handler itself, as nldd-radio-button-group already did.
  • Arrow navigation skipped the rows inside an open branch. arrow-navigation on a type="tree" list walked only the top-level rows, so ArrowDown jumped over a branch's children to the next branch. It now follows the rows in the order they appear on screen.
  • A row divider ran through the focus ring of a segmented action. The divider is rendered after the row's content, so it painted over a ring that reaches past its own box. A focused action now sits above it.
  • The first focus ring after loading a page could stay away. The input-modality tracker only started listening once a component asked it something, which is at the first focus — so someone tabbing straight into a freshly loaded page had already pressed Tab by then, the modality still read "mouse", and the control suppressed its ring. It now listens from the moment the module loads.
  • An app without a split view scrolled its page instead of the document. nldd-app-view derived the scroll mode from the outermost horizontal split view and left it unset when there was none, so those apps fell back to nested scrolling — and on iOS that costs the rubber-band and the collapsing browser toolbar. A bare-page app is a single column at every width, so it now scrolls the document. Set --context-scroll-mode on the nldd-app-view itself if you want it otherwise.
  • A tree row inside a branch could not be reached with Shift+Tab. The rows that are not the current one carried tabindex="-1", and a shadow host with a tabindex is a focus scope of its own: Chromium walks straight past such a scope when tabbing backwards if the host itself isn't tabbable. So once you had tabbed out of the tree from a nested row, the whole list was skipped on the way back, while forward navigation still found it. Rows that are not current now carry no tabindex at all.
  • A focus ring inside a branch was cut off by its own children. A row paints its children group right after the row, in the same stacking context, so on an open branch the bottom of the ring disappeared under the first child. The focused row now sits above its group — and with focus in a child, the child still wins.
  • The last row of a tree drew a divider against the frame. A boxed list withholds the divider of its last row, but "last" was read from the list's own rows only, so an open branch's last child kept its line — a stray divider hard against the bottom of the box. The list now walks into open branches to find the row that really paints last, and follows along as branches open and close.
  • A branch's own divider overlapped its first child. The line under a row hangs in a 1px margin, but on a branch that margin sat after the whole subtree: the divider under the branch fell on top of the first child, and an extra line's worth of space ended up under the last one. The margin now sits under the row itself, where the divider is.
  • A nested row no longer shows the press state of the rows above it. A branch's child rows are light-DOM children, so their pointer events travel through every ancestor row: pressing a leaf lit up its whole ancestry for a moment. A row now ignores presses that started in a row nested inside it.
  • nldd-menu scrolls the highlighted item into view. During keyboard navigation the consumer sometimes keeps focus (the combo box leaves it in the input), so the browser does not scroll along. The menu now scrolls the minimum: nothing when the item is already visible, one row when stepping past an edge, and all the way back on wrap-around.
  • nldd-sheet and nldd-window report closing through every route, and ignore closes that are not theirs. The public close event came only from hide(), but Escape on a modeless overlay closes through the browser's CloseWatcher, which the cancel handler cannot reliably stop — a modeless sheet closed silently. In the other direction, a nested component (a date field's popover, say) dispatches its close with composed and bubbles, and that reached the same listener: the sheet emitted its own close while it stayed open, and consumers tore down content on an event that was not theirs. Both now emit from whichever route actually closed, once per open cycle, and only from their own dialog.
  • nldd-window and nldd-modal-dialog no longer close on a drag that ends on the backdrop. Selecting text or dragging a control inside the overlay and releasing outside counted as a backdrop click. Light dismiss now requires the press and the release to both land on the backdrop, the guard nldd-sheet already had.
  • nldd-sheet and nldd-window take no space in the flow. Both render a position: fixed dialog, so the host only added an empty box. As a block it was a flex item like any other, and inside an nldd-split-view-pane it collected the pane's ::slotted flex-grow and ate the height its siblings needed. Both are display: contents now, matching nldd-modal-dialog and nldd-tooltip.
  • nldd-popover moves focus itself on Tab. Safari does not tab into the contents of a top-layer element: with the popover focused it skipped the whole thing and landed on whatever followed in the document, leaving the popover open behind you. Tab and Shift+Tab now walk the popover's own focusables.
  • nldd-popover absorbs the first tap outside itself on a small screen. There it renders as a bottom sheet with a dimmed backdrop, but a popover backdrop is paint and not a barrier, so one tap dismissed the sheet and activated whatever sat under the dimming.
  • nldd-popover: Tab got stuck inside a popover holding a roving-tabindex widget (a calendar grid, a toolbar). The focus scan counted every tabindex="-1" element as focusable, so with a calendar inside it saw 41 day buttons.
  • nldd-toolbar hangs its overflow menu in its own shadow root. On document.body the menu went inert (visible but untouchable) as soon as the toolbar sat inside a modal dialog, since everything outside that dialog is inert then. The menu is a popover, so it escapes clipping through the top layer anyway. Each toolbar also gets its own menu id (two toolbars on a page shared one), and a single remaining fluid child now fills the row instead of stopping at half.
  • nldd-page-footer aligns the legal bar to the right when there are no start items. Without them the end area was the only flex child and space-between put it at the start.
  • nldd-side-by-side-split-view and nldd-stacked-split-view follow the scroll mode. Two of the five split views never took part in the root-scroll distribution, so on a narrow screen they kept clipping at viewport height while the layers inside them had already handed their scrolling to the document. Nothing scrolled at all.
  • nldd-just-in-time-education no longer shows the browser's own focus ring around the whole box, text and arrow included. The container takes focus on open so Escape and the dismiss button are reachable, and it now carries the design system's ring, with an offset, and only when the coach mark was opened from the keyboard.
  • Text selection on controls — buttons, menu items, tabs and other controls no longer show a selection highlight when dragged over on iOS and older Safari (-webkit-user-select alongside the standard property).

Configuration

📅 Schedule: (in timezone Europe/Amsterdam)

  • Branch creation
    • "before 6am on sunday"
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate.

This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [@nldd/design-system](https://github.com/MinBZK/storybook) | [`^0.8.70` → `^0.8.77`](https://renovatebot.com/diffs/npm/@nldd%2fdesign-system/0.8.70/0.8.77) | ![age](https://developer.mend.io/api/mc/badges/age/npm/@nldd%2fdesign-system/0.8.77?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@nldd%2fdesign-system/0.8.70/0.8.77?slim=true) | --- ### Release Notes <details> <summary>MinBZK/storybook (@&#8203;nldd/design-system)</summary> ### [`v0.8.77`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0877-2026-08-02-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.76...v0.8.77) - fix(popover): clear a stale centering transform when the override goes ([#&#8203;166](https://github.com/MinBZK/storybook/issues/166)) ([81ee9e8](https://github.com/MinBZK/storybook/commit/81ee9e8)), closes [#&#8203;166](https://github.com/MinBZK/storybook/issues/166) ##### Fixed - **`nldd-popover`** — a popover that loses its `centered` (or edge) override at runtime no longer keeps the centering transform. The override branch cleared `transform` only while it was still being taken, so a responsive popover switching from centered to anchored on a breakpoint change kept `translate(-50%, …)` on top of Floating UI's coordinates and landed half its width off its anchor, partly off screen. Floating UI positions purely through `left`/`top`, so the transform is now cleared whenever no override applies. ### [`v0.8.76`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0876-2026-08-02-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.75...v0.8.76) - fix(menu): set aria-haspopup on the anchor from first render ([#&#8203;165](https://github.com/MinBZK/storybook/issues/165)) ([2486d28](https://github.com/MinBZK/storybook/commit/2486d28)), closes [#&#8203;165](https://github.com/MinBZK/storybook/issues/165) ##### Fixed - **`nldd-menu`** — a button that opens a menu now carries `aria-haspopup` from the first render instead of from its first open. `aria-haspopup` describes the trigger ("this button opens a menu"), not a state, and deferring it left a screen reader tabbing a row of identical "more" buttons hearing plain "button" — precisely when the type matters, since nothing has been opened yet. Because `popup-type` also decides whether `aria-expanded` is rendered at all, a button without `expandable` had neither attribute until first use. `nldd-popover` already worked this way; the two now agree. Setting `popup-type` yourself still wins, so no markup has to change. ### [`v0.8.75`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0875-2026-08-01-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.74...v0.8.75) - feat: font-free stylesheet entry, month picker, markdown code blocks and open-source docs ([#&#8203;164](https://github.com/MinBZK/storybook/issues/164)) ([263ffd6](https://github.com/MinBZK/storybook/commit/263ffd6)), closes [#&#8203;164](https://github.com/MinBZK/storybook/issues/164) ##### Highlights - **Month and year each have their own menu.** The heading showed both with one chevron and opened a list of years only. Changing the month went by arrow, one step at a time, so a month on the other side of the year took up to six clicks. Both menus offer only what `min` and `max` allow. "Vandaag" moved out of the heading to the bottom left, which is what makes room for a month written out in full. The calendar in `nldd-date-field` opens under the input as well, instead of running off to the right of it ([#&#8203;156](https://github.com/MinBZK/storybook/issues/156)). - **Open-source documentation expanded.** A code of conduct, a route for reporting vulnerabilities, a support page, a description of who decides what, and a `publiccode.yml` for the catalogue on developer.overheid.nl. The contributing guide grew from a page of changelog conventions into an actual guide ([#&#8203;149](https://github.com/MinBZK/storybook/issues/149)). - **Host styling now survives a consuming app's CSS reset.** A universal rule like `* { margin: 0; padding: 0; border: 0 }` in a consuming app silently beat every normal `:host` declaration (CSS Scoping cascade order, [#&#8203;160](https://github.com/MinBZK/storybook/issues/160)), stripping padding, dividers, and spacing from components that styled their shadow host. Banner, container, menu groups and dividers, table rows, cells, and interactive list rows now keep their layout under any reset, including Tailwind Preflight. Styling remains a CSS-variables affair — direct element styling such as `nldd-banner { padding: … }` was never a supported API and now consistently has no effect. - **New icons.** `viewfinder-line` (alias `scan`) is the existing `viewfinder` with a scan line through it, for scanning a document or a code. `display` and `paintbrush` landed in the same batch. ##### Added - **Icons** — `viewfinder-line` (alias `scan`), `display`, `paintbrush`. - **`nldd-card`** — a `background` attribute: `base` (default) or `tinted`, for a card that has to lift off a base surface. Customize with `--components-card-tinted-*`. - **`@nldd/design-system/styles/system-font`** — the same stylesheet as `/styles`, without the `@font-face` rules. Both family stacks end in a system font, so they fall through on their own; nothing needs overriding. For products that may not use the Rijksoverheid house fonts (see `NOTICES.md`). - **`@nldd/design-system/styles/variables`** — only the CSS custom properties, for a build that composes the stylesheets itself. - **`@nldd/design-system/breakpoints`** — the breakpoints for `matchMedia` and layout logic, previously behind `/tokens`. ##### Changed - **`nldd-date-picker`** — the heading read "September 2026" with a chevron, promising both, and opened a list of years only ([#&#8203;156](https://github.com/MinBZK/storybook/issues/156)). Month and year are now each their own button with their own menu, so a month on the other side of the year is two clicks instead of up to six on an arrow. "Vandaag" moves out of the heading to the bottom left, where the stacked layout already had it; that is what makes room for a month written out in full. The heading no longer wraps between month and year. The month and year buttons stand as tall as the paging controls beside them (32px, 44px stacked) instead of bare 22px text, which also satisfies the WCAG 2.5.8 target size. Both menus offer only what `min` and `max` allow, and a part with a single reachable value drops its chevron and its menu rather than opening to confirm what you already see. - **`nldd-date-picker`** — the day numbers carry medium weight. Weight was doing no work in the calendar (today is a ring, selected is a fill), so it was free to separate the dates from the chrome around them: the weekday headers and the week numbers now recede together ([#&#8203;156](https://github.com/MinBZK/storybook/issues/156)). - **`nldd-title`** — a slotted heading is capped at a 40ch measure and balances its lines, so a title on a wide section no longer runs the full width with a lonely last word. - **`nldd-list-item`** — a row that opens with an icon now starts its divider at the first text or title cell, so the line aligns with the words instead of the icon. Consumers no longer need a `divider-start` marker for this; an explicit marker still wins, and putting one on the icon cell restores the full-width line. - **Document typography** — the stylesheet now gives the `body` the document font and content color as soon as an `nldd-app-view` is on the page. Apps no longer need their own `body { font: … }`. The rule sits in `@layer reset`, so any consumer rule beats it without effort; a page without an app-view is untouched. ##### Breaking - **`@nldd/design-system/tokens` is gone.** It only ever re-exported `breakpoints`, so import from `@nldd/design-system/breakpoints` instead. Same values, same names. - **The four `--primitives-font-family-*-fallback` variables are gone.** Nothing read them, so overriding one to drop RijksSans changed nothing while looking like the switch you were after. To use a different font, override `--primitives-font-family-sans-serif` and `--primitives-font-family-monospace` — or import `/styles/system-font` and skip the `@font-face` rules entirely. ##### Fixed - **`nldd-date-field`** — the calendar hangs off the trigger, which sits at the end of the field, and opened rightward from there: on a 192px field it ran 302px past the field's right edge and barely overlapped the input it belonged to. It now opens leftward, landing under the input; against the left edge of the screen Floating UI falls back to the old direction on its own ([#&#8203;156](https://github.com/MinBZK/storybook/issues/156)). - **`nldd-rich-text`** — a markdown renderer emits a fenced code block as `<pre><code>`, and the tinted chip meant for inline code painted once per rendered line, so a three-line block showed three separate boxes ([#&#8203;158](https://github.com/MinBZK/storybook/issues/158)). The frame now sits on the `pre`, where the block is, and the `code` inside hands the chip back. It carries the same inset ring as `nldd-box` and `nldd-code-viewer`, so the block stays readable on a tinted surface instead of dissolving into it. - **`nldd-rich-text`** — a `pre` had no `overflow-x`, so a single long code line escaped the element and stretched every ancestor with it. In a narrow card that read as rich-text ignoring the card width. Long lines now scroll inside the block, as a table already did. - **`nldd-date-picker`** — activating a paging arrow or "Vandaag" pulled focus into the day grid, so paging twice meant finding the arrow again. Focus now stays on the control that was activated; only the roving tabindex moves along, so tabbing into the grid still lands on the equivalent day. - **`nldd-date-field` and `nldd-password-field`** — the embedded button's focus ring carries a 6px halo meant to land exactly on the field's border, but the field's `overflow: hidden` clipped it at the padding box, leaving the border to cut through the ring. The clip is gone: nothing in either field can escape without it (the input clips its own text, and the autofill background is overridden inside the input), so the ring now paints over the field the way it does over any other neighbour. - **`nldd-popover`** — after any mouse interaction, tabbing through the popover showed no focus rings. The popover intercepted every Tab and moved focus itself (a Safari workaround), but a script-moved focus only inherits the ring state of the element it left, where a browser-moved one gets a ring unconditionally — so one ringless start poisoned every stop after it. The popover now intercepts only the hop off the container (the one Safari cannot make) and the boundary that closes it; every Tab in between is the browser's. That entry hop also serves a click on the popover's dead chrome: Tab then starts at the top of the popover instead of resuming from wherever focus happened to be. - **`nldd-tooltip`** — activating the trigger now dismisses the tooltip. It sat in the top layer above the popover that very click had opened, because manual popovers paint over auto ones that enter later. - **`nldd-collection`** — the previous/next arrows in `layout="horizontal-scroll"` stepped by a fixed distance, so from the end of the strip (never a whole number of items) every item stayed clipped. The arrows now snap to the nearest item edge. - **`nldd-collection`** — reaching an end with the keyboard disabled the arrow you were standing on, and a disabled control cannot hold focus, so focus fell to the body and the next Tab restarted at the top of the page. Focus now moves to the sibling arrow. - **`nldd-container`** — `layout="lanes"` and `layout="columns"` ignored `sm-gap`, `md-gap` and `lg-gap` and always used the base `gap`. Every layout now reads one resolved gap, so the per-breakpoint values apply to multicol too. - **`nldd-banner`** — the visual frame (background, inset border, corner radius, padding, grid) moved from the host to a wrapper inside the shadow root, out of reach of document CSS. Use `--components-banner-*` to customize. - **`nldd-container`** — the padding and the query container moved to a wrapper inside the shadow root (host > `.container` > `.container__inner`), out of reach of document CSS; size queries still measure the same padded interior width. - **`nldd-menu-group` and `nldd-menu-divider`** — dividers, spacing, and padding moved to elements inside the shadow root, out of reach of document CSS; their `flow-root` hosts keep that spacing interior, so menus keep their grouping and rhythm under a reset. - **`nldd-table-row`, the cell family, and interactive `nldd-list-item` rows** — row dividers, row padding (`--context-cell-padding-block`), and the widened inset of interactive rows shield their host declarations, since subgrid participation and negative margins cannot move into the shadow tree. ### [`v0.8.74`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0874-2026-08-01-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.73...v0.8.74) - docs: add EUPL-1.2 LICENSE file and ship third-party notices ([#&#8203;148](https://github.com/MinBZK/storybook/issues/148)) ([e7791ea](https://github.com/MinBZK/storybook/commit/e7791ea)), closes [#&#8203;148](https://github.com/MinBZK/storybook/issues/148) [#&#8203;132](https://github.com/MinBZK/storybook/issues/132) ### [`v0.8.73`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0873-2026-07-30-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.72...v0.8.73) - feat: 32 nieuwe iconen, icon-gallery met statusfilter en fine-tuning ([#&#8203;163](https://github.com/MinBZK/storybook/issues/163)) ([0425e4d](https://github.com/MinBZK/storybook/commit/0425e4d)), closes [#&#8203;163](https://github.com/MinBZK/storybook/issues/163) ##### Highlights - **37 new icons.** Sound and image (`microphone`, `speaker` and its volume steps, `photo-camera`, `video-camera`, `photo-on-photo-angled` for a gallery, `photo-stack`), maps and wayfinding (`map`, `map-pin` and its badge variants, `map-pin-oval` for your current location, `signpost` for directions), a fuller file and folder family (`file-badge-*`, `file-on-file`, `folder-open`, `folder-badge-plus`), `arrow-clockwise` for refresh, a pair of expand and collapse arrows, `clipboard-pencil` for a form, `hand-thumbs-up` and `hand-thumbs-down` for a like and a dislike, `person-badge-minus`, `link-badge-lock` for a secure link, `slider-horizontal-3` for local settings, `text-format-size`, and `square-grid-2x2` with a pencil variant. The full list is under Added. - **11 icons are redrawn.** The file and folder family (`file`, `file-text` and its badge and pencil variants, `file-text-on-file-text`, `folder`), the stack icons (`rectangle-stack`, `rectangle-stack-text`, `rectangle-stack-chevron-left-forward-slash-chevron-right`) and `house-apartment-building` got new artwork, so the set draws with one pen again now that it has grown. ##### Added - **Icons** — `apartment-building-2` (aliases `buildings` and `offices`), `arrow-clockwise` (aliases `refresh` and `reload`), `arrow-down-left-arrow-up-right` (aliases `expand` and `full-screen`), `arrow-up-right-arrow-down-left` (aliases `collapse` and `exit-full-screen`), `clipboard-pencil` (alias `form`), `file-badge-arrow-down` (alias `download-document`), `file-badge-arrow-up` (alias `upload-document`), `file-badge-minus` (alias `remove-document`), `file-badge-plus` (alias `new-document`), `file-on-file` (alias `documents`), `folder-badge-plus` (alias `new-folder`), `folder-open`, `hand-thumbs-up` (alias `like`), `hand-thumbs-down` (alias `dislike`), `link-badge-lock` (aliases `secure-link` and `secure-url`), `map`, `map-pin` (alias `location`), `map-pin-badge-plus` (alias `add-location`), `map-pin-badge-minus` (alias `remove-location`), `map-pin-oval` (alias `current-location`), `microphone` (alias `microphone-on`), `microphone-slash` (alias `microphone-off`), `person-badge-minus` (alias `remove-user`), `photo-camera` (alias `camera`), `photo-on-photo-angled` (alias `gallery`), `photo-stack` (aliases `image-stack` and `images`), `signpost` (alias `directions`), `slider-horizontal-3` (alias `local-settings`), `speaker`, `speaker-slash` (alias `mute`), `speaker-volume-low` (alias `low-volume`), `speaker-volume-medium` (alias `medium-volume`), `speaker-volume-high` (alias `high-volume`), `square-grid-2x2`, `square-grid-2x2-pencil`, `text-format-size` and `video-camera`. ##### Changed - **Step indicator and timeline track cell, fine-tuned.** The current step's fill is one step lighter, the number in the marker is one weight heavier (medium), and a minor dot on the plain track grew from 8px to 10px (a minor step marker stays 12px). - **The icon gallery shows what changed.** The tiles of the latest icon batch carry a "Nieuw" or "Bijgewerkt" tag, and a segmented control next to the search field filters on "Alles", "Nieuw" and "Bijgewerkt". - **The `refresh` and `reload` aliases point at the new `arrow-clockwise`.** They sat on `arrow-2-counter-clockwise`, which keeps `sync` — two arrows chasing each other read as synchronization, one clockwise arrow as a refresh. - **`file-text-pencil` gains the `edit-text-document` alias**, next to `new-text-document` and `add-text-document` on its check-plus sibling. - **The dismiss icons gain `close` aliases**: `close` for `dismiss`, and `close-circle`, `close-circle-filled`, `close-small` and `close-extra-small` for their variants. - **`rectangle-stack` is redrawn and gains the `library` alias**, next to the existing `stack`. - **`stack-code` is now the alias of `rectangle-stack-chevron-left-forward-slash-chevron-right`.** The icon is renamed (and redrawn) after the shape-first pattern of `chevron-left-forward-slash-chevron-right`; the old name keeps working as its functional alias. - **The `documents` alias points at `file-on-file`.** It sat on the icon now called `file-text-on-file-text`, which keeps `text-documents` — the plain pair is the generic plural, the way `document` already sat on plain `file`. ##### Breaking - **Three icons renamed**, because `-stack` is reserved for 3 or more and these draw 2: `file-text-stack` is now `file-text-on-file-text` (with new artwork), `folder-stack` is now `folder-on-folder`, and `tag-stack` is now `tag-on-tag`. The old names are gone. The aliases `text-documents`, `directories`, `tags` and `labels` moved along and keep working. - **`stack-text` is now `rectangle-stack-text`** (with new artwork), naming the shape it draws the way `rectangle-stack` already does. - **`house-and-appartment-building` is now `house-apartment-building`** (with new artwork) — the spelling fixed to match `apartment-building`, and the "and" dropped from the compound. - **`square-and-arrow-down` is now `square-arrow-down`**, dropping the "and" the way `square-arrow-up` and `square-arrow-right-top` already read. The aliases `save` and `import` moved along and keep working. - **The media-transport icons carry a `media-` prefix**: `backward`, `forward` and their `-filled`, `-end`, `-end-filled`, `-frame` and `-frame-filled` variants are now `media-backward`, `media-forward` and so on (12 renames). The bare names were ambiguous — "forward" reads as navigation more often than as media transport — and the icon `forward` was unreachable outright, shadowed by the alias `forward` → `chevron-right` (aliases win on resolution). That alias stays, as the counterpart of `back` → `chevron-left`. `play`, `pause`, `stop` and `play-pause` keep their names: they collide with nothing and are clear as they are. ### [`v0.8.72`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0872-2026-07-29-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.71...v0.8.72) - fix(timeline-track-cell): laat het spoor over de rijgrens doorlopen ([#&#8203;162](https://github.com/MinBZK/storybook/issues/162)) ([950d6c1](https://github.com/MinBZK/storybook/commit/950d6c1)), closes [#&#8203;162](https://github.com/MinBZK/storybook/issues/162) ##### Fixed - **The timeline track broke at every row.** An `nldd-list-item` reserves a divider's worth of space below itself, and the lines of `nldd-timeline-track-cell` stopped at the cell's edge — leaving a hairline gap between one row's track and the next. The lines that run on downward now bridge that band. ### [`v0.8.71`](https://github.com/MinBZK/storybook/blob/HEAD/CHANGELOG.md#small0871-2026-07-29-small) [Compare Source](https://github.com/MinBZK/storybook/compare/v0.8.70...v0.8.71) - feat: step indicator, tree lists and a reworked list-item ([#&#8203;161](https://github.com/MinBZK/storybook/issues/161)) ([2c87577](https://github.com/MinBZK/storybook/commit/2c87577)), closes [#&#8203;161](https://github.com/MinBZK/storybook/issues/161) ##### Highlights - **New `nldd-step-indicator` for a process of several steps.** A row of markers carrying a number (or a check mark once a step is done), a label below each and a track in between. `current` on the parent derives every step's status (`past`, `current`, `future`); a step can override it. A finished step is filled with a check mark, the current one is an accent outline on a light accent field around its number, and what is still to come is a quiet grey field. With `href` or `button` a step becomes a control, so you can page back — also in a flow without a URL per step. Below the sm breakpoint (measured on the container) it collapses to one line of text plus a segmented bar, with the full list of steps still in the DOM for assistive technology. Horizontal only: steps below one another are a list of `nldd-timeline-track-cell`. - **A list can be a tree.** `nldd-list type="tree"` makes the list a `role="tree"` of `treeitem` rows; a branch's child rows go in that row's `children` slot, which the item renders as a `role="group"` and hides while `expanded` is off. The nesting *is* the hierarchy, so level, position and set size are derived rather than authored. Disclosure works two ways: a chevron of its own (`nldd-list-item-action[disclosure]`) or the row itself as the control (`button` plus `expanded`), where an `nldd-icon-cell` marked `disclosure` turns along. Indentation stays the consumer's: repeat a spacer-cell per level. A tree brings its own keyboard, see below. - **`nldd-timeline-track-cell` is now the vertical counterpart of the step indicator.** With `variant="step"` the marker carries a number or icon and you have a step list below one another; by default it stays the bare track for a timeline of events. - **A tree comes with its own keyboard.** `type="tree"` is a composite widget, so it no longer waits for `arrow-navigation`: up and down move between the rows in the order they appear on screen (the rows of an open branch included), Home and End jump to the ends, Right opens a closed branch and steps into an open one, Left closes an open branch and steps out of a leaf, and Enter and Space open and close from the row itself. Opening and closing runs through the row's own disclosure control, so `expanded` keeps being written in one place — your handler; a row that is a link is never activated that way. The tree is one tab stop: focus lands on the row (that is where `treeitem` sits, so the row gets announced rather than a button inside it), wearing the system's own focus ring around the row rather than the browser's outline around the whole open branch, and Tab then walks the controls of that row, a chevron beside a checkbox included. Deliberately between two patterns: a row with several controls is strictly a `treegrid`, and we keep the tree semantics while borrowing Tab-within-the-row from the grid. - **New icons.** `bug`, `square`, `square-1` (alias `primary`), `triangle-square-circle` (alias `categories`), `book-badge-plus` (alias `new-book`), `tag-stack` (aliases `tags` and `labels`, for a set of labels where `tag` is one) and `person-text-rectangle` (alias `contact-card`), plus the aliases `add-text-document` for `file-text-badge-check-plus`, `announcement` for `megaphone` and `company` for `apartment-building`. The alias `category` for `tag` is gone: a label is not a category, and beside the new `categories` (`triangle-square-circle`) the two read as the same thing. Use `tag` or `label`. - **Surfaces carry their boundary with a border, from one family of tokens.** The border colour of base and tinted surfaces is the divider colour (one step lighter in light mode than before), its thickness is `--semantics-surfaces-border-width` and the corner radius `--semantics-surfaces-corner-radius` (10px). Cards, boxes, boxed lists, tables, the code viewer and the sidebar box all follow from that one place, and `nldd-card` loses its drop shadow to become an ordinary base surface. In dark mode the card used to be a lighter field that happened to stand out; now the border carries it in both schemes. ##### Breaking - `nldd-list-item` — the `start` and `end` slots are gone. Put the cells that sat there (avatars, spacers, icons) in the row itself, in the same place. The divider spans the full content width by default; if you used the slots to start it later or stop it earlier (after an avatar, say), mark the cell where it should begin or end with `divider-start` or `divider-end`. Without `divider-start` it starts at the front, without `divider-end` it runs to the end. The `children` slot for nested rows stays. The hover and selection fill of an interactive row is now genuinely clickable across the full painted width. - `nldd-list-item-action` — a **segmented action**: an action covering part of the row, as opposed to the row-wide action `nldd-list-item` renders itself with `href` or `button`. Segmented actions now own a fixed inline padding and are at least as wide as the row's control size (md 44px, sm 32px), so the hit area is a square at minimum. Remove spacer cells you added inside one for room or hit area — the action handles that itself now, and leaving them in doubles the space. Icon-only actions (a chevron in a tree) get slightly wider. An action at a row edge shifts 8px towards that edge, so its outer edge lands exactly where a row-wide action's hit area begins and its contents sit on the same grid as the text of an ordinary row. It shifts, it does not grow: the width stays the control size. If you reserve the chevron zone on leaf rows in a tree, watch rows without an indent spacer in front — there a branch row's action shifts along and the zone sits 8px further out. An action mid-row is unaffected. - `nldd-timeline-track-cell` — the attributes have new names. `step` is `status` (same values, the same vocabulary as `nldd-step-indicator-item`), `child` is `position` (it is about the place in the sequence, not a DOM relation), and the size is no longer picked in pixels but through `variant`: `dot` (default, a bare track) or `step` (a 24px marker with a number or icon in it). - **The serif tokens are gone.** `--primitives-font-family-serif` and `-serif-fallback` pointed at `RijksoverheidSerif`, a font the system does not ship and no component used. If you referenced them, set your own stack. - **Three corner-radius tokens are gone**, because all three said the same thing in three places: `--components-box-corner-radius`, `--components-list-corner-radius` and `--components-sidebar-section-sidebar-box-corner-radius`. Every surface now takes its radius from `--semantics-surfaces-corner-radius`; that is the only place to round them off, or square them off. New alongside it is `--semantics-surfaces-border-width`, so border and divider move together in thickness as well. Both sit at family level, because base and tinted share them (the border colours stay per variant). - **Two icons renamed.** `rectangle-chevron-left-forward-slash-chevron-right` is now `chevron-left-forward-slash-chevron-right-rectangle`, so the shape it sits in comes last, the way the other names read. And `square-corner-4` is now `viewfinder` — four loose corners describe the drawing, not what it does. Their aliases `code-block` and `fit-to-view` are unchanged and remain the names to reach for. - **The icon alias `category` is gone.** It pointed at `tag`, and next to the new `categories` alias (which points at `triangle-square-circle`) the pair suggested two views of one thing while they are different concepts. `icon="category"` no longer resolves; use `tag` or `label`. - **`nldd-radio-button-field._commitFormValue()` is `commitFormValue()`.** The method was meant for `nldd-radio-button-group` (which calls it on the siblings it unchecks) but was public; it now comes from the shared mixin and therefore drops the underscore. - **`accessible-labelled-by` is now `accessible-labeled-by`** on `nldd-segmented-control`, `nldd-radio-button-group` and `nldd-toggle-button-group`; the property is `accessibleLabeledBy`. The system writes US English, also where the HTML spec does not: the forwarded `aria-labelledby` keeps its own spelling, because that one belongs to the spec. - **Translation keys for aria labels now end in `-label`.** `-label-text` said it twice, since the type already says it is a label. Renamed: `list.items-label-text` → `list.items-accessible-label`, `list.navigation-label-text` → `list.navigation-accessible-label`, `list.search-placeholder-text` → `list.search-placeholder-label`, `drag-handle-cell.label-text` → `drag-handle-cell.accessible-label`, `progress-bar.label-text` and `progress-circle.label-text` → `accessible-label`, their `loading-text` → `loading-label`, `activity-indicator.loading-text` → `loading-label`, `badge.notification-text` → `notification-label`, `token-field.removable-hint` → `removable-lowercase-label`, and `opens-in-new-tab-text` → `opens-in-new-tab-label` on `nldd-list-item`, `nldd-card`, `nldd-link`, `nldd-avatar`, `nldd-button` and `nldd-icon-button`. `pagination.accessibility-label` is now `pagination.accessible-label`, as everywhere else. The texts themselves are unchanged; if you override a key through `translations`, update the name. - **Two translation keys turned US English:** `components.list.reorder-cancelled-text` and `components.document-tab-bar.reorder-cancelled-text` are now `reorder-canceled-text`. Update the key if you override it through `translations`; the Dutch default text is unchanged. - **Every token that feeds a `border-width` is now named that way.** `--semantics-input-fields-border-thickness`, `--components-checkbox-border-thickness`, `--components-radio-button-border-thickness`, `--components-radio-button-is-selected-inner-shape-border-thickness`, `--components-switch-border-thickness`, `--components-switch-thumb-border-thickness` and `--components-keyboard-shortcut-border-thickness` end in `-border-width`. The value comes from `--primitives-border-width-*` and goes into a `border-width`, so renaming it halfway only bought a word to remember. A line that is not a border keeps `thickness`: `--semantics-dividers-thickness` feeds a `height`, and `--semantics-dividers-width` would read as how wide a divider is. - The internal context variable `--context-list-item-min-size` is now `--context-list-item-size`. Only relevant if you hooked into it yourself. ##### Added - **`nldd-step-indicator` and `nldd-step-indicator-item`** (status & feedback) — new. On the parent: `current` (1-based), `accessible-label` and `translations`. On a step: `text`, `icon`, `status` (overrides what the parent derives), `href` or `button`. - **`nldd-list`** — `type="tree"`, plus the `children` slot and `expanded` on `nldd-list-item` for branch rows. `disclosure` on an `nldd-icon-cell` turns the chevron along with `expanded`. - **`divider-start` and `divider-end` on cells** — let the row divider begin or end at a cell (after the avatar, say). Several markers together span from the first start to the last end. - **`nldd-timeline-track-cell`** — `variant` (`dot` / `step`), `minor` for a row that belongs under the one above it (a smaller marker in the same lane, so the track runs straight and nothing indents), `text` and `icon` for what the marker carries, and `direction="up"` for a timeline with the newest at the top. - **`nldd-avatar`** — `href`, `target`, `rel`, `button` and `accessible-label`: the disc itself becomes the control, so hit area and focus ring follow the round shape instead of a square overlay, and the initials get no underline. The name comes from `accessible-label`, or else from `name`; `href` wins over `button`, as with `nldd-card`. - **`nldd-button`** — `max-width`: caps the button at a CSS length, also alongside `width="full"` (follow the container, but no wider than this). A label that doesn't fit is truncated with an ellipsis, because a cap the content ignores isn't a cap. - **`nldd-window`** — `no-light-dismiss`: a click beside the window no longer closes it, while Escape and the dismiss button keep working. For windows where dismissing by accident costs work, such as a wizard or a filled-in form. - **`nldd-icon`** — `size="full"` names the existing behaviour (fill whatever sizes you) and `size="inherit"` makes the icon follow the surrounding text (1em), for an icon set in a sentence. Reach for the latter rather than your own `nldd-icon { width: 1em }` rule: such a rule wins over the component and also shrinks the icons a cell or button was already sizing correctly. - **`nldd-date-picker`** — `width`: `full` or a CSS length, next to the intrinsic seven-cell width. - **`nldd-menu`** — the `anchorElement` property positions the menu against an element without turning it into a toggle. For a menu you open yourself (a type-ahead under a text field), where the `anchor` attribute would swallow the click on the anchor. ##### Changed - **`nldd-card` has no drop shadow and is an ordinary base surface.** Field, border and corner radius come from the same `--semantics-surfaces-base-*` family as a boxed `nldd-list` or `nldd-table`. `--components-card-box-shadow` is `none`; set it back if you want the shadow. - **The boundary between two rows is real space now, not paint a row withholds.** An `nldd-list-item` has a 1px bottom margin and the divider hangs in it, so a hover or selection fill runs to the row's own edge. That retires the internal context variable `--context-list-item-boundary-inset`, which existed only so a slotted `nldd-list-item-action` could withhold the same pixel. A list grows 1px per row; if you measure row positions yourself, count the margin in. While dragging, the divider of the lifted row and of its drag clone is hidden. - **Boxed lists: fills sit 4px clear of the frame, and the frame no longer clips.** The rows sit far enough inside the frame that their fills never reach its corners, so the `overflow: hidden` that rounded them off against it could go — a focus ring inside a box now paints outward like every other control instead of being cut off 4px away. The row fill follows suit and rounds off a step more tightly (6px), concentric with the 10px frame around it. Content and dividers do not move; no action needed. - **A row can be its own disclosure control and still turn its chevron.** Mark the chevron's `nldd-icon-cell` with `disclosure` and `nldd-list-item` rotates it with `expanded`, the same affordance `nldd-list-item-action[disclosure]` already gave. Until now a tree had to choose: a chevron that turns (only the chevron clickable) or a fully clickable row (a chevron that never moves). - **`nldd-checkbox-field` and `nldd-radio-button-field` are form-associated.** They submit `value` under `name`, exactly like `nldd-checkbox` and `nldd-radio-button`; previously the inner control sat unreachable in the field's shadow root and the value never made it into the form. `nldd-radio-button-group` keeps exactly one value in the form while the `change` event is still propagating, so a consumer serialising in its own listener (htmx, `new FormData(form)`) never sees two. Both support `form.reset()` and reflect `name`. - **All eighteen form-associated inputs share one `FormAssociated` mixin.** `formAssociated`, the `ElementInternals`, `formDisabledCallback` and the moment of committing sat in eighteen files, each with its own `_syncFormValue`. A component now supplies only what is its own: `formValue()`, and `formState()` where the value alone cannot rebuild the control. The timing rule lives in one place: the value is committed on every render *and* has to be committed again from the handler itself with `commitFormValue()`, because a render is a task later than the event. Nothing changes on the outside, except that `internals`, `formValue()` and `commitFormValue()` now exist on each of those components. - **`nldd-table` hands its row padding to the cells**, through the same `--context-cell-padding-block` the list uses. The inline padding stays on the row, so the full-bleed divider does not move. - **`nldd-code-viewer` and the sidebar box follow the surface tokens.** Both took a hard-coded 1px border, and the viewer its own `corner-radius-lg`; border width and corner radius now come from `--semantics-surfaces-border-width` and `--semantics-surfaces-corner-radius`, so they move along with every other surface instead of drifting on their own. - **`nldd-box` takes its border width from a token.** The 1px was hard-coded in the `box-shadow`; there is now `--components-box-border-width` (defaulting to `--semantics-surfaces-border-width`), and the border is painted from one composed variable, as in `nldd-card`. - **`nldd-collection` decides its gap on container width**, not only on the viewport, and grid children get `min-width: 0`. One long unbreakable string in a card used to stretch its whole column, and every consumer had to catch that themselves. - **`nldd-avatar`: the initials are a step smaller and lighter**, and optically centred. Capitals do not use the space below the baseline, so centring on the em box left them sitting visibly high. - **`nldd-form-field`: more room above help and error text**, equal to the space between label and control. - **The monospace stack has real fallbacks.** Behind `JetBrains Mono` stood the generic `monospace` alone, which on many systems is Courier New: thinner, narrower and with a smaller x-height, so code looked entirely different while the web font had not loaded (or never arrived). `ui-monospace`, `Menlo`, `Consolas` and `DejaVu Sans Mono` now come first. - **`nldd-top-navigation-bar`: wordmark, title space and focus ring.** The wordmark text wraps within the logo instead of running on as a sentence, the website title next to the menu bar gets the same padding on its right as the menu items (so the hover state no longer bumps into it), and the focus ring of the logo link sits around the ribbon instead of the whole block. ##### Fixed - **The component reference was missing eight components.** `nldd-menu`, `nldd-menu-item`, `nldd-menu-divider`, `nldd-menu-group`, `nldd-breadcrumbs-item`, `nldd-button-bar-divider`, `nldd-page-footer-legal-bar` and `-legal-bar-item` did not appear in `skills/nldd/reference.md`: their documentation sits above their own class rather than at the top of the file, and the generator only read the first block. It now reads every block that names its element with `@element`. - **A label of `nldd-form-field` slid over a sticky header.** The field's header deliberately sits above its own input (`z-index: 1`), but without a stacking context of its own that z-index competed in the page's nearest context and beat the sticky title bar the field scrolls under. The field now isolates itself. - **`nldd-form` let hidden fields take up space.** The gap hung as `margin-top` on every following child, so an `<input type="hidden">` (formset bookkeeping, framework plumbing) pushed the first visible field down. The gap now hangs below the preceding child, and hidden children render no box. - **An `nldd-button` in a flex or grid parent had an invisible full-width box.** The host stretched with the column while the button inside stayed content-sized, so the element was several times wider than what you see — surprising when you inspect it, and it swallows clicks that look like they land beside the button. The host now has a definite width and only stretches with `width="full"`. - **A focused `nldd-card` lost the halo around its focus ring.** The ring was drawn on the card itself, combining the card's own box-shadow token with the ring's in one declaration — and that token is `none`, which cannot sit in a comma-separated shadow list, so the whole declaration was dropped. The outline still showed, the white halo that separates it from the background did not. The ring now sits in its own layer beside the card, where the card's overflow can't clip it either. - **`nldd-card` with `href` showed the hand cursor.** The overlay link now follows `--semantics-controls-link-cursor`, like `nldd-link` and an `nldd-list-item` with `href`. - **`nldd-collection` used the small gap at large widths** when it sat inside a container-query ancestor (a card, a page, a window, a sheet). The viewport rule was right, its container-query twin read the sm token. - **`nldd-window` emitted `close` for a `close` from its own contents.** A nested overlay (the popover of a date field, say) fires a composed, bubbling `close` that reaches the window's own listener: consumers tore the window down while it stayed open, and the real close was then swallowed. `nldd-sheet` already guarded against this; the window now does too. - **A radio `nldd-toggle-button-group` briefly had two values in the form.** Deselecting the other buttons waited for their next render, so a consumer serialising the form in its own `change` listener (htmx, `new FormData(form)`) saw both the old and the new value. The group now commits the deselected buttons from the handler itself, as `nldd-radio-button-group` already did. - **Arrow navigation skipped the rows inside an open branch.** `arrow-navigation` on a `type="tree"` list walked only the top-level rows, so ArrowDown jumped over a branch's children to the next branch. It now follows the rows in the order they appear on screen. - **A row divider ran through the focus ring of a segmented action.** The divider is rendered after the row's content, so it painted over a ring that reaches past its own box. A focused action now sits above it. - **The first focus ring after loading a page could stay away.** The input-modality tracker only started listening once a component asked it something, which is at the first focus — so someone tabbing straight into a freshly loaded page had already pressed Tab by then, the modality still read "mouse", and the control suppressed its ring. It now listens from the moment the module loads. - **An app without a split view scrolled its page instead of the document.** `nldd-app-view` derived the scroll mode from the outermost horizontal split view and left it unset when there was none, so those apps fell back to nested scrolling — and on iOS that costs the rubber-band and the collapsing browser toolbar. A bare-page app is a single column at every width, so it now scrolls the document. Set `--context-scroll-mode` on the `nldd-app-view` itself if you want it otherwise. - **A tree row inside a branch could not be reached with Shift+Tab.** The rows that are not the current one carried `tabindex="-1"`, and a shadow host with a tabindex is a focus scope of its own: Chromium walks straight past such a scope when tabbing backwards if the host itself isn't tabbable. So once you had tabbed out of the tree from a nested row, the whole list was skipped on the way back, while forward navigation still found it. Rows that are not current now carry no tabindex at all. - **A focus ring inside a branch was cut off by its own children.** A row paints its children group right after the row, in the same stacking context, so on an open branch the bottom of the ring disappeared under the first child. The focused row now sits above its group — and with focus in a child, the child still wins. - **The last row of a tree drew a divider against the frame.** A boxed list withholds the divider of its last row, but "last" was read from the list's own rows only, so an open branch's last child kept its line — a stray divider hard against the bottom of the box. The list now walks into open branches to find the row that really paints last, and follows along as branches open and close. - **A branch's own divider overlapped its first child.** The line under a row hangs in a 1px margin, but on a branch that margin sat after the whole subtree: the divider under the branch fell on top of the first child, and an extra line's worth of space ended up under the last one. The margin now sits under the row itself, where the divider is. - **A nested row no longer shows the press state of the rows above it.** A branch's child rows are light-DOM children, so their pointer events travel through every ancestor row: pressing a leaf lit up its whole ancestry for a moment. A row now ignores presses that started in a row nested inside it. - **`nldd-menu` scrolls the highlighted item into view.** During keyboard navigation the consumer sometimes keeps focus (the combo box leaves it in the input), so the browser does not scroll along. The menu now scrolls the minimum: nothing when the item is already visible, one row when stepping past an edge, and all the way back on wrap-around. - **`nldd-sheet` and `nldd-window` report closing through every route, and ignore closes that are not theirs.** The public `close` event came only from `hide()`, but Escape on a `modeless` overlay closes through the browser's CloseWatcher, which the `cancel` handler cannot reliably stop — a modeless sheet closed silently. In the other direction, a nested component (a date field's popover, say) dispatches its `close` with `composed` and `bubbles`, and that reached the same listener: the sheet emitted its own `close` while it stayed open, and consumers tore down content on an event that was not theirs. Both now emit from whichever route actually closed, once per open cycle, and only from their own dialog. - **`nldd-window` and `nldd-modal-dialog` no longer close on a drag that ends on the backdrop.** Selecting text or dragging a control inside the overlay and releasing outside counted as a backdrop click. Light dismiss now requires the press and the release to both land on the backdrop, the guard `nldd-sheet` already had. - **`nldd-sheet` and `nldd-window` take no space in the flow.** Both render a `position: fixed` dialog, so the host only added an empty box. As a block it was a flex item like any other, and inside an `nldd-split-view-pane` it collected the pane's `::slotted` flex-grow and ate the height its siblings needed. Both are `display: contents` now, matching `nldd-modal-dialog` and `nldd-tooltip`. - **`nldd-popover` moves focus itself on Tab.** Safari does not tab into the contents of a top-layer element: with the popover focused it skipped the whole thing and landed on whatever followed in the document, leaving the popover open behind you. Tab and Shift+Tab now walk the popover's own focusables. - **`nldd-popover` absorbs the first tap outside itself on a small screen.** There it renders as a bottom sheet with a dimmed backdrop, but a popover backdrop is paint and not a barrier, so one tap dismissed the sheet and activated whatever sat under the dimming. - **`nldd-popover`: Tab got stuck inside a popover holding a roving-tabindex widget** (a calendar grid, a toolbar). The focus scan counted every `tabindex="-1"` element as focusable, so with a calendar inside it saw 41 day buttons. - **`nldd-toolbar` hangs its overflow menu in its own shadow root.** On `document.body` the menu went inert (visible but untouchable) as soon as the toolbar sat inside a modal dialog, since everything outside that dialog is inert then. The menu is a popover, so it escapes clipping through the top layer anyway. Each toolbar also gets its own menu id (two toolbars on a page shared one), and a single remaining fluid child now fills the row instead of stopping at half. - **`nldd-page-footer` aligns the legal bar to the right when there are no start items.** Without them the end area was the only flex child and `space-between` put it at the start. - **`nldd-side-by-side-split-view` and `nldd-stacked-split-view` follow the scroll mode.** Two of the five split views never took part in the root-scroll distribution, so on a narrow screen they kept clipping at viewport height while the layers inside them had already handed their scrolling to the document. Nothing scrolled at all. - **`nldd-just-in-time-education`** no longer shows the browser's own focus ring around the whole box, text and arrow included. The container takes focus on open so Escape and the dismiss button are reachable, and it now carries the design system's ring, with an offset, and only when the coach mark was opened from the keyboard. - **Text selection on controls** — buttons, menu items, tabs and other controls no longer show a selection highlight when dragged over on iOS and older Safari (`-webkit-user-select` alongside the standard property). </details> --- ### Configuration 📅 **Schedule**: (in timezone Europe/Amsterdam) - Branch creation - "before 6am on sunday" - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4yODAuNSIsInVwZGF0ZWRJblZlciI6IjQzLjI4MC41IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiXX0=-->
robbertbos force-pushed renovate/nldd from 7ac306db05
All checks were successful
CI / pre-commit (pull_request) Successful in 1m14s
CI / frontend-test (pull_request) Successful in 4m41s
CI / backend-test (pull_request) Successful in 6m36s
CI / release-scripts (pull_request) Successful in 12s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 53s
security-scan / Python SAST (bandit) (pull_request) Successful in 34s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 24s
security-scan / JS SCA (npm audit) (pull_request) Successful in 40s
security-scan / SBOM (trivy) (pull_request) Successful in 16s
CI / backend-test-postgres (pull_request) Successful in 9m51s
test-build / build (backend) (pull_request) Successful in 1m51s
test-build / build (frontend) (pull_request) Successful in 2m16s
test-build / build (pull_request) Successful in 0s
CI / e2e (pull_request) Successful in 9m57s
to 3cc2ef6d57
Some checks failed
CI / pre-commit (pull_request) Failing after 3m7s
CI / backend-test (pull_request) Successful in 4m32s
CI / release-scripts (pull_request) Successful in 10s
CI / frontend-test (pull_request) Successful in 4m2s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 1m1s
security-scan / Python SAST (bandit) (pull_request) Successful in 37s
security-scan / JS SCA (npm audit) (pull_request) Successful in 38s
security-scan / SBOM (trivy) (pull_request) Successful in 17s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 26s
CI / backend-test-postgres (pull_request) Successful in 10m5s
test-build / build (backend) (pull_request) Successful in 2m1s
test-build / build (frontend) (pull_request) Successful in 2m23s
test-build / build (pull_request) Successful in 0s
CI / e2e (pull_request) Successful in 10m34s
2026-08-03 02:02:39 +00:00
Compare
robbertbos changed title from Update dependency @nldd/design-system to ^0.8.75 to Update dependency @nldd/design-system to ^0.8.77 2026-08-03 02:02:43 +00:00
Author
Owner

Held back from the bundled bump round (#218) on purpose - this one needs a code change and two design calls, so it should not ride along with routine bumps.

Blocker: 0.8.75 removed the four --primitives-font-family-*-fallback tokens. frontend/src/styles/tokens.css:46-47 points the family chain at them deliberately, because we may not use RijksSans (licensing note is in that file). Without those tokens the var() reference is invalid at computed-value time, so --primitives-font-family-sans-serif and the downstream --primitives-font-family-body both compute to the empty string, which drops the body { font: ...; font-family: ... } rule in base.css entirely.

Measured on the built bundle in Chromium:

0.8.70 0.8.77
font-family system-ui, sans-serif Times
font-size 18px 16px
line-height 27px normal

Typecheck, eslint, vitest, e2e and the build all pass on 0.8.77, so no gate we run catches this.

Fix options: set a literal stack (--primitives-font-family-sans-serif: system-ui, sans-serif;) and drop the serif line (--primitives-font-family-serif no longer exists in 0.8.77), or import @nldd/design-system/styles/system-font, which 0.8.75 added for exactly this case - though that entry still names RijksSans first in the stack, so an explicit override is the safer route for the licensing constraint.

Two visual changes to decide on as well:

  • --components-card-box-shadow default went level-1 -> none in 0.8.71. CardShell.vue relies on that default for the resting state, so cards lose their resting shadow and are carried by the border alone. Hover, focus-visible and dragging overrides still work.
  • 0.8.75 moved the banner frame off :host into a shadow wrapper. RetentionIntroBanner carries a compensating padding rule that now stacks on top of the inner padding (double-padded, and the tinted frame shrinks 12px per side), while the seven banners without that rule silently gain the correct interior padding.

Checked and clear: all 34 icon names we use survive the 21 icon renames in 0.8.71/0.8.73, and vue-tsc does not newly fail - every prop union we touch is unchanged or widened.

Held back from the bundled bump round (#218) on purpose - this one needs a code change and two design calls, so it should not ride along with routine bumps. **Blocker: 0.8.75 removed the four `--primitives-font-family-*-fallback` tokens.** `frontend/src/styles/tokens.css:46-47` points the family chain at them deliberately, because we may not use RijksSans (licensing note is in that file). Without those tokens the `var()` reference is invalid at computed-value time, so `--primitives-font-family-sans-serif` and the downstream `--primitives-font-family-body` both compute to the empty string, which drops the `body { font: ...; font-family: ... }` rule in `base.css` entirely. Measured on the built bundle in Chromium: | | 0.8.70 | 0.8.77 | |---|---|---| | `font-family` | `system-ui, sans-serif` | `Times` | | `font-size` | 18px | 16px | | `line-height` | 27px | normal | Typecheck, eslint, vitest, e2e and the build all pass on 0.8.77, so no gate we run catches this. Fix options: set a literal stack (`--primitives-font-family-sans-serif: system-ui, sans-serif;`) and drop the serif line (`--primitives-font-family-serif` no longer exists in 0.8.77), or import `@nldd/design-system/styles/system-font`, which 0.8.75 added for exactly this case - though that entry still names RijksSans first in the stack, so an explicit override is the safer route for the licensing constraint. **Two visual changes to decide on as well:** - `--components-card-box-shadow` default went level-1 -> `none` in 0.8.71. `CardShell.vue` relies on that default for the resting state, so cards lose their resting shadow and are carried by the border alone. Hover, focus-visible and dragging overrides still work. - 0.8.75 moved the banner frame off `:host` into a shadow wrapper. `RetentionIntroBanner` carries a compensating padding rule that now stacks on top of the inner padding (double-padded, and the tinted frame shrinks 12px per side), while the seven banners without that rule silently gain the correct interior padding. Checked and clear: all 34 icon names we use survive the 21 icon renames in 0.8.71/0.8.73, and `vue-tsc` does not newly fail - every prop union we touch is unchanged or widened.
Author
Owner

Replaced by #219, which takes 0.8.77 rebased on current main together with the two code changes the upgrade needs (the font-chain fix in tokens.css and the removal of RetentionIntroBanner's compensating padding rule). Full risk analysis is in that PR's description.

Replaced by #219, which takes 0.8.77 rebased on current main together with the two code changes the upgrade needs (the font-chain fix in tokens.css and the removal of RetentionIntroBanner's compensating padding rule). Full risk analysis is in that PR's description.
robbertbos closed this pull request 2026-08-05 12:16:58 +00:00
robbertbos referenced this pull request from a commit 2026-09-19 12:56:59 +00:00
robbertbos referenced this pull request from a commit 2026-09-19 13:12:43 +00:00
Some checks failed
CI / pre-commit (pull_request) Failing after 3m7s
Required
Details
CI / backend-test (pull_request) Successful in 4m32s
Required
Details
CI / release-scripts (pull_request) Successful in 10s
Required
Details
CI / frontend-test (pull_request) Successful in 4m2s
Required
Details
security-scan / Python SCA (pip-audit) (pull_request) Successful in 1m1s
Required
Details
security-scan / Python SAST (bandit) (pull_request) Successful in 37s
Required
Details
security-scan / JS SCA (npm audit) (pull_request) Successful in 38s
Required
Details
security-scan / SBOM (trivy) (pull_request) Successful in 17s
Required
Details
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 26s
Required
Details
CI / backend-test-postgres (pull_request) Successful in 10m5s
Required
Details
test-build / build (backend) (pull_request) Successful in 2m1s
Required
Details
test-build / build (frontend) (pull_request) Successful in 2m23s
Required
Details
test-build / build (pull_request) Successful in 0s
Required
Details
CI / e2e (pull_request) Successful in 10m34s
Required
Details

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robbertbos/waggle!212
No description provided.