enhancement
major
major
major
#29866
Design System wave 4b: app shell, app bar, sidebar and bottom bar read the design system package
Continues #29836 (wave 4a, overlays). Own ticket so that a release between the two merges does not close the ticket of the open one. The layout containers (TLPanel, TLSplitPanel, TLCard, TLStack, TLGrid, TLDeckPane, TLTileStack, TLInset, TLAdaptiveDetail, TLAccordion, TLWizard, TLViewError) follow in wave 4c with a ticket of their own.
Problem
The app shell of the React view layer – TLAppShell, TLAppBar, TLSidebar (with its mobile drawer and flyout), TLBottomBar and the hamburger TLDrawerToggle – is styled by the old stylesheet tlReactControls.css. The same jobs are done several times in different ways:
- Two drawers: the off-canvas sidebar has no Escape, no focus handling, no aria-hidden, and is glued to the app bar by a literal top: 3.5rem.
- The sidebar flyout computes its own position without flip or tracking and runs out of the window; role=menu is built by hand.
- Navigation entries in sidebar, flyout and bottom bar have three anatomies; the active one is marked by a class only, without aria-current.
- Sidebar collapse has no aria-expanded; the hamburger reports neither aria-expanded nor aria-controls.
- App bar and bottom bar repeat the height 3.5rem as a literal.
- No <main> landmark; aria-label="Bottom navigation" fixed English; breakpoint 768 kept separately in TSX and CSS.
Solution
Decisions in the package TopLogic/tl-design-system (spec docs/superpowers/specs/2026-10-16-welle-4b-navigation-design.md, reasons in docs/skalen.md "Welle 4b: Navigation", forecast Q10–Q14 in docs/migration/altlast.md):
- Only TLAppShell measures the breakpoint and passes it on as context (useDisplayClass) and as data-tl-display; no component stylesheet has a width media query. The content area is the <main> landmark.
- On small screens the sidebar renders its navigation in the modal drawer of wave 4a (focus trap, Escape, scrim; focus returns to the hamburger). The hamburger exists only there and reports aria-expanded / aria-controls from server state.
- Collapsed, a sidebar group opens its children as Menu at the new placement right-start.
- Entries carry the anatomy of tl-menu__item; the current page is aria-current="page" and carries the selection surface, also on the head of a collapsed group containing it. A count at an icon's corner is the container tl-icon-badge.
- App bar and bottom bar share the size token size-shell-bar (48px, 40px compact); the elevated app bar is separated by a line; the app bar gives way with its toolbar first, then the title.
- The bottom bar names itself in the user's language.
Also carried by this wave: the empty table's focus ring was clipped by tl-table (found by the new browser test focus-clip.test.mjs in the package); it is now drawn inside.
Migration
- The CSS classes tlAppShell*, tlAppBar*, tlSidebar*, tlBottomBar* and tlDrawerToggle no longer exist. Application stylesheets that target them must be rewritten against the package classes and attributes; the full old → new list is in the package (docs/migration/altlast.md, "Welle 4b").
- The breakpoint is measured by the app shell alone. Rules for small screens read [data-tl-display~="compact"] on .tl-app-shell instead of @media (max-width: 768px).
- Visible: the app bar is 48px high instead of 56 (40 in compact density); the elevated app bar is separated by a line instead of a shadow; the current page carries the selection surface instead of a bar at its left; on small screens the sidebar is a modal drawer over the app bar; the hamburger button exists only on small screens; bottom bar labels are 12px.