Morph Label
betaWords that morph in place when they change: the width eases to the new words while the old ones blur out and the new ones blur in.
Preview
press
refused
status
Not saved yet
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/morph-label
Use it for
- Words that change where people are looking, like Follow to Following, Save to Saved, or a short status beside a value.
- Use MorphLabel explicitly when a word change needs the blur treatment. Button uses MotionSwap for its default crossfade.
- Whatever holds it grows or shrinks with it, so a button eases to its new width instead of snapping.
Avoid it for
- Long text or a paragraph. It is for a few words on one line. Words wider than the space end in an ellipsis, so in a flex row give the box that holds it min-w-0.
- Words that change many times a second, like a timer. Use Rolling Number for numbers that count.
- Saying something only through the change. Words that matter, like an error, also need a role="alert" or role="status" so they are read out.
Props
- children
The words. When they change, the old ones blur out as the new ones blur in.
string | number
- className
Extra classes on the label. Later classes win.
string
| Prop | Type | Default | What it does |
|---|---|---|---|
| children | string | number | - | The words. When they change, the old ones blur out as the new ones blur in. |
| className | string | - | Extra classes on the label. Later classes win. |
Accessibility
- Screen readers read only the new words. The old words are hidden from them while they fade.
- It does not announce the change. Put it in a live region, or add a role="status" message, when the change must be heard.
- The morph follows the --motion-* tokens. Reduced motion lands the new width at once and keeps only the fade, in place. With motion off, the words swap at once.
Examples
Words that change on a press
const [following, setFollowing] = useState(false);
<Button emphasis={following ? "soft" : "solid"} onClick={() => setFollowing((on) => !on)}>
{following ? "Following" : "Follow"}
</Button>A short status that changes in place
<p className="text-sm text-muted-foreground" role="status">
<MorphLabel>{saving ? "Saving…" : "Saved just now"}</MorphLabel>
</p>