Kinetic Typography

Type Specimen Stage

A variable-font showcase in the style of a foundry specimen page — a giant glyph, a weight ladder, and a size ramp — where dragging an axis slider makes the whole specimen tween and reflow in sync with Motion.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add "https://webberui.com/r/type-specimen-stage.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

Active edited usageDefault props
<TypeSpecimenStage/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add "https://webberui.com/r/type-specimen-stage.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/type-specimen-stage.

Usage

import { TypeSpecimenStage } from "@/components/ui/type-specimen-stage";

<TypeSpecimenStage
  glyph="Ag"
  sampleText="Grotesk"
  fontName="Webber Grotesk"
  defaultAxisValues={{ wght: 520, wdth: 108, opsz: 40 }}
/>

Controlled mode: pass axisValues and onAxisValuesChange to own the axis state yourself.

const [axes, setAxes] = React.useState({ wght: 400, wdth: 100, opsz: 16 });

<TypeSpecimenStage axisValues={axes} onAxisValuesChange={setAxes} />

Show only some of the axis sliders:

<TypeSpecimenStage axes={["wght", "opsz"]} />

Props

PropTypeDefaultDescription
glyphstring"Ag"The giant main glyph (a single character or short word)
sampleTextstring"Typeface"Sample text shared by the weight ladder column and the size ramp
fontFamilystringsystem sans stackSpecimen font family; pass a variable font to get real axis rendering
foundrystring"Webber Type Foundry"Foundry information in the header
fontNamestring"Webber Grotesk Variable"Font name shown in the header
axes("wght" | "wdth" | "opsz")[]all three axesWhich axis sliders to show (in order)
weightsnumber[][200,300,400,500,700,900]Weight list of the weight ladder (top to bottom)
sizesnumber[][14,20,28,40,56]Size list of the size ramp (px)
axisValuesPartial<Record<Axis, number>>—Controlled axis values (passing them enables controlled mode)
defaultAxisValuesPartial<Record<Axis, number>>each axis's built-in defaultInitial axis values in uncontrolled mode
onAxisValuesChange(values) => void—Callback when the axis values change

How it works

  • Axis mapping: each of the three axes maps to a reliably visible CSS lever, so the specimen reflows visibly even on a system font with no variable axes — wght → font-weight, wdth → horizontal scaleX, opsz → tracking.
  • Real variable fonts: the component also outputs font-variation-settings, so if you point fontFamily at a genuine variable font, wght / wdth / opsz render through the font's native axes.
  • Synchronized tweening: behind every slider is a useSpring motor, so dragging makes the whole specimen (the giant glyph, the weight ladder, and the size ramp) approach the target value smoothly on the same spring.
  • Weight ladder: each row carries its own weight, and font-weight drives a variable font's wght axis directly; the row whose weight is closest to the current slider value is marked by a highlight bar that slides along as you drag.

Accessibility

  • The sliders at the bottom use native <input type="range">, with built-in keyboard operation (arrow keys) and aria-label / aria-valuetext.
  • The axis readouts in the header carry aria-live="polite", so assistive technology announces the current axis values live as you drag.
  • The repeated specimen visuals (the ladder rows and the size ramp, but not the giant glyph) are marked aria-hidden to keep readers from repeating the same sample text.
  • When the user has "reduce motion" enabled at the system level, the axis values jump straight to their targets (MotionValue.jump) with no reveal or tween animation.