How to build an accessible LargeTitleHeader in React

The component owns the scroll container, so the sticky bar and the scroll timeline cannot be broken by surrounding markup. The title is a real h1–h3 in normal flow, so heading order and document outline are unaffected; the copy mirrored into the sticky bar is aria-hidden so screen readers announce the title exactly once. The collapse is a CSS scroll-driven animation with no client JavaScript, so the header is complete in server-rendered HTML and nothing depends on hydration. Where animation-timeline is unsupported the mirror stays hidden and the header degrades to a sticky bar above a heading — no content is lost. Under prefers-reduced-motion the reveal snaps with steps(1, jump-end) instead of interpolating. The bar clears the coarse-pointer target floor and pads for the top safe-area inset.

When to use a LargeTitleHeader

When not to use it

Accessibility

Role heading, verified at WCAG 2.2-AA.

Common mistakes

Avoid: Rendering it inside a parent with no resolved height

Prefer: Give the parent a height (a grid/flex track, a dvh value, or 100% of a sized ancestor)

The component is the scroll container at block-size 100%; with an auto-height parent it never scrolls, so the title never collapses

Avoid: Passing the page heading again as the first child of the content below

Prefer: Let the component own the heading

The component already renders a real h1–h3; repeating it duplicates the heading in the accessibility tree

Example

<LargeTitleHeader title="Library">
  <List>
    <ListItem>Recently Added</ListItem>
    <ListItem>Artists</ListItem>
    <ListItem>Albums</ListItem>
  </List>
</LargeTitleHeader>

See the full LargeTitleHeader reference →