KQ-1506 · SHY/LABEL

Shy Label

A text field whose label sits inside it and steps aside as you type: focus lifts it above the field on springs.glide with its letters hopping in a ripple from the caret's side, leaving a faint imprint inside, and as the text reaches the imprint each nearby letter hops up and away along a curved, tipping path on its own spring, shrinks and flies to its twin in the raised label, which hops on springs.flick and settles on springs.recoil as its letter regroups. Deleting brings the letters back down on springs.glide. Validation slides the message 4 px into place on glide over the hint while the border, label and an end icon popping in on snap take the state's colour; it is a real input with a real label, so the keyboard, selection and autofill are the browser's own.

KQ-1506 · SHY/LABEL

The Coldbrook Steep

Brew notes and new roasts, monthly.

We send one letter a month.

empty · checked when you leave

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/shy-label

Props

label
string
default —
The field's label: inside the field at rest, above it once there is focus or text. Its accessible text is a real <label for>.
value / defaultValue
string
default — / ""
The text, controlled or uncontrolled.
onValueChange
(value: string) => void
default —
Fires on every edit with the new text.
hint
string
default —
A line under the field while there is no validation message.
state
"default" | "success" | "error"
default "default"
The validation state: the border, raised label and an end icon take its colour, and message slides in under the field.
message
string
default —
Shown and announced under the field for success and error; the hint returns for default.
type
"text" | "email" | "password" | "search" | "tel" | "url"
default "text"
The input's type; a password measures its dots for the caret.
name
string
default —
A form field name for the input.
autoComplete
string
default —
Passed to the input.
scatter
number
default 0.6
How lively the letters are as they step aside, 0 to 1: 0 just fades them, 1 sends them on high, tilting arcs.
reach
number
default 20
How far ahead of the caret, in px, a letter starts to step aside.
size
"sm" | "md" | "lg"
default "md"
Field height (40, 48 or 56 px) and type size.
color
"cobalt" | "signal" | "ember" | "rose" | string
default "cobalt"
The focused border and raised label: a preset tuned for both themes or any CSS colour.
required
boolean
default false
Passed to the input.
disabled
boolean
default false
Disables the input and dims the field.
onFocus / onBlur
(event: React.FocusEvent<HTMLInputElement>) => void
default —
The input's focus handlers, e.g. to validate on blur.
className
string
default —
Classes for the outer column.