Motion UIComponentsComponent

Shrink header

A fixed header that condenses from full-height and transparent into a compact solid bar on scroll.

npx shadcn@latest add @motion/shrink-header

API reference

Components

<ShrinkHeader />

The fixed header root. Owns the page useScroll, turns scroll depth into a spring-smoothed condense progress and the derived fill scale / row recentre offset, and publishes them to its parts via context. Its <header> is fixed to the top of the viewport at a constant tallHeight - the height NEVER animates; the fill layer inside it scales instead.

children?

ReactNode

The header contents: a ShrinkHeaderFill and a ShrinkHeaderRow (which wraps your wordmark, nav and CTA).

condenseDistance?

number = DEFAULT_CONDENSE_DISTANCE

Scroll distance (px) over which the header condenses from transparent and full-height to solid and compact. Defaults to 220.

tallHeight?

number = DEFAULT_TALL_HEIGHT

The header's constant height (px) at the top of the page. Defaults to 104. Never animates - the fill layer scales instead.

compactHeight?

number = DEFAULT_COMPACT_HEIGHT

The fill's visual height (px) once fully condensed. Defaults to 54.

className?

string

Merged onto the <header> element, last. The header is fixed to the top at full width; use this for a font base, extra z-index, etc.

<ShrinkHeaderFill />

The background-only fill layer. It is aria-hidden (pure chrome, no text), pinned to the header bounds, and scales vertically from its TOP edge (scaleY, origin-top) while fading its opacity in as the header condenses - so the bar visually shrinks from full-height-transparent to compact-solid and its border/shadow/blur "fade in" as one with the fill's own opacity. Both are compositor-only transforms. Must be rendered inside a <ShrinkHeader>.

className?

string

Merged onto the fill element, last - override the surface, border, shadow or blur here. The defaults (a hairline bottom border, a soft shadow, a backdrop blur and the translucent card tone) are the condensed-bar chrome; pass classes to tune them.

style?

CSSProperties

Merged onto the fill element's inline style, last, so a consumer can override the default translucent tone.

<ShrinkHeaderRow />

The content row. Rides a translateY (derived from the same condense progress) so its contents stay vertically centred against the visually-smaller fill as the header condenses. Sits above the fill (z-10) and fills the header height. Must be rendered inside a <ShrinkHeader>.

children?

ReactNode

The row contents: your wordmark, nav and CTA. Scale them yourself off useCondenseProgress so they condense with the bar.

className?

string

Merged onto the row element, last. Use it for the row's layout - measure, centring, horizontal padding, flex distribution.

Hooks

useCondenseProgress

Returns the enclosing ShrinkHeader's raw condense progress MotionValue (0 at the top of the page, 1 once fully condensed). Scale your own clusters off it - useTransform(condense, [0, 1], [1, 0.82]) for a wordmark that shrinks to 82%, say - or derive any other condense-linked transform. Throws if called outside a ShrinkHeader.

useCondenseProgress(): MotionValue<number>