23rd

Stretchy Footer

Dia-style rubber overscroll — pull past the bottom and a rainbow aurora stretches up, then springs back when you let go.

Not a scroll-progress footer reveal — an overflow rubber-band. In the preview, scroll past the end (or hit Show effect): the page lifts on a spring and a stepped pyramid of blurred gradient columns (magenta through sunlight to deep navy) stretches up to fill the gap. Every column has its own spring, so the top edge ripples as it snaps back. Swap palettes, blur, glow, and snap below, or Flip it into a valley — tall edges, dipped middle — so the ripple runs in from the sides. Rotate 180° turns the aurora upside down in place: same pull past the bottom, but the columns hang from the lifted page with the gradient reversed.

Preview

Scroll past the end of this card — or play the rubber-band from here.

Tip: keep scrolling after you hit the bottom.

Props
Palette
220
9
16
0
380

Tall edges, dipped middle

Aurora hangs from the page

Installation

pnpm dlx shadcn@latest add @23rd/stretchy-footer

Or install straight from the public GitHub source registry:

pnpm dlx shadcn@latest add radiumcoders/23rd.dev/stretchy-footer

Usage

Use it as the scroll viewport. Put your page (and a normal footer block) in children. Wheel or touch past the bottom stretches the aurora with a rubber-band falloff; scrolling back up retraces it, and letting go snaps it home. Trackpad momentum can't re-pull it, and nested scrollers such as code blocks keep their own wheel. Honors prefers-reduced-motion (no stretch). One vanilla engine drives both the React and Svelte versions, and it doesn't need motion.

"use client"

import { StretchyFooter } from "@/components/ui/stretchy-footer"

export function Page() {
  return (
    <StretchyFooter className="h-svh bg-background">
      <main className="min-h-[120%] px-8 py-24 text-foreground">
        {/* …page content… */}
      </main>
      <footer className="px-8 pb-10 text-center text-muted-foreground">
        23rd — opinionated UI for shippers
      </footer>
    </StretchyFooter>
  )
}

On a full document (window scroll), pass windowScroll and mark the page root with data-stretchy-page so the content rolls up into the aurora:

"use client"

import { StretchyFooter } from "@/components/ui/stretchy-footer"

export function DocsChrome() {
  return (
    <>
      <div data-stretchy-page>{/* page content */}</div>
      <StretchyFooter windowScroll />
    </>
  )
}

Props

PropTypeDefault
childrenReactNode / snippet—
scrollRefRefObject<HTMLElement | null>React — self as scroller
scrollElHTMLElementSvelte — self as scroller
windowScrollbooleanfalse
contentSelectorstring[data-stretchy-page]
maxStretchnumber280
colorsstring[]magenta → navy — gradient stops, top to floor
stiffnessnumber380
dampingnumber32
columnsnumber9 — steps down from the middle
blurnumber16 — px
glownumber0 — white floor bloom, 0–1
flipbooleanfalse — tall edges, dipped middle
rotate0 | 1800 — 180 hangs the aurora from the page
labelstringStretchy overflow — scroll region label
demoIdstring— pairs with playStretchyFooterDemo({ target })
classNamestringReact only
classstringSvelte only