Floating Label Input
An input component with a label that floats above the field when focused or filled. Uses a compound component pattern (FloatingLabel, FloatingLabel.Input, FloatingLabel.Label) for full styling control. Inspired by shadcn/ui Expansions.
Installation
Section titled “Installation”npx shadcn@latest add https://joaocarmassi.com/components/floating-label-input.jsonpnpm dlx shadcn@latest add https://joaocarmassi.com/components/floating-label-input.jsonnpx shadcn@latest add https://joaocarmassi.com/components/floating-label-input.jsonbunx --bun shadcn@latest add https://joaocarmassi.com/components/floating-label-input.jsonThe direct URL serves the radix-vega variant. The Floating Label Input is style-aware — its underlying input height, radius, and label offsets differ per shadcn style. To let the CLI pick the variant that matches your project’s theme automatically, register the @prisma namespace once (see Styles & Themes) and install by name:
npx shadcn@latest add @prisma/floating-label-inputpnpm dlx shadcn@latest add @prisma/floating-label-inputnpx shadcn@latest add @prisma/floating-label-inputbunx --bun shadcn@latest add @prisma/floating-label-inputImport
Section titled “Import”import { FloatingLabel } from '@/components/ui/floating-label-input';Preview
Section titled “Preview”<FloatingLabel> <FloatingLabel.Input id='email' type='email' /> <FloatingLabel.Label htmlFor='email'>Email</FloatingLabel.Label></FloatingLabel>Multiple Fields
Section titled “Multiple Fields”<div className='flex flex-col gap-4'> <FloatingLabel> <FloatingLabel.Input id='name' /> <FloatingLabel.Label htmlFor='name'>Full Name</FloatingLabel.Label> </FloatingLabel> <FloatingLabel> <FloatingLabel.Input id='email' type='email' /> <FloatingLabel.Label htmlFor='email'>Email</FloatingLabel.Label> </FloatingLabel> <FloatingLabel> <FloatingLabel.Input id='password' type='password' /> <FloatingLabel.Label htmlFor='password'>Password</FloatingLabel.Label> </FloatingLabel></div>Custom Styling
Section titled “Custom Styling”Each sub-component accepts its own className, giving full control without extra wrapper props.
<FloatingLabel> <FloatingLabel.Input id='username' className='rounded-full border-primary/50 px-5 focus:border-primary' /> <FloatingLabel.Label htmlFor='username' className='left-3 text-primary'> Username </FloatingLabel.Label></FloatingLabel>With Field (Description)
Section titled “With Field (Description)”Wrap FloatingLabel inside a shadcn Field to add descriptions, errors, and accessible form layouts.
We'll never share your email.
import { Field, FieldDescription } from '@/components/ui/field';<Field> <FloatingLabel> <FloatingLabel.Input id='email' type='email' /> <FloatingLabel.Label htmlFor='email'>Email</FloatingLabel.Label> </FloatingLabel> <FieldDescription>We'll never share your email.</FieldDescription></Field>With Field (Error)
Section titled “With Field (Error)”Use data-invalid on Field and aria-invalid on the input to show validation errors.
import { Field, FieldError } from '@/components/ui/field';<Field data-invalid> <FloatingLabel> <FloatingLabel.Input id='email' type='email' aria-invalid /> <FloatingLabel.Label htmlFor='email'>Email</FloatingLabel.Label> </FloatingLabel> <FieldError>Enter a valid email address.</FieldError></Field>With Field (Validation)
Section titled “With Field (Validation)”A complete example with interactive validation — the error appears when the input loses focus and the value is too short.
Must be at least 3 characters.
'use client';
import { useState } from 'react';import { FloatingLabel } from '@/components/ui/floating-label-input';import { Field, FieldDescription, FieldError } from '@/components/ui/field';
export function FieldValidationDemo() { const [value, setValue] = useState(''); const [touched, setTouched] = useState(false);
const isInvalid = touched && value.length < 3;
return ( <Field data-invalid={isInvalid || undefined}> <FloatingLabel> <FloatingLabel.Input id='username' value={value} onChange={(e) => setValue(e.target.value)} onBlur={() => setTouched(true)} aria-invalid={isInvalid || undefined} /> <FloatingLabel.Label htmlFor='username'>Username</FloatingLabel.Label> </FloatingLabel> <FieldDescription>Must be at least 3 characters.</FieldDescription> {isInvalid && ( <FieldError>Username must be at least 3 characters.</FieldError> )} </Field> );}With FieldSet (Form)
Section titled “With FieldSet (Form)”Group multiple floating label inputs inside a FieldSet with FieldGroup for a complete form layout.
import { Field, FieldDescription, FieldGroup, FieldSet, FieldLegend,} from '@/components/ui/field';<FieldSet> <FieldLegend>Account Information</FieldLegend> <FieldDescription>Fill in your account details below.</FieldDescription> <FieldGroup> <Field> <FloatingLabel> <FloatingLabel.Input id='name' /> <FloatingLabel.Label htmlFor='name'>Full Name</FloatingLabel.Label> </FloatingLabel> </Field> <Field> <FloatingLabel> <FloatingLabel.Input id='email' type='email' /> <FloatingLabel.Label htmlFor='email'>Email</FloatingLabel.Label> </FloatingLabel> <FieldDescription> We'll send a confirmation to this address. </FieldDescription> </Field> <Field> <FloatingLabel> <FloatingLabel.Input id='password' type='password' /> <FloatingLabel.Label htmlFor='password'>Password</FloatingLabel.Label> </FloatingLabel> <FieldDescription>Must be at least 8 characters.</FieldDescription> </Field> </FieldGroup></FieldSet>FloatingLabel (root)
Section titled “FloatingLabel (root)”| Prop | Type | Default | Description |
|---|---|---|---|
children |
React.ReactNode |
— | Must contain .Input and .Label. |
className |
string |
— | Additional CSS classes for the root wrapper. |
FloatingLabel.Input
Section titled “FloatingLabel.Input”| Prop | Type | Default | Description |
|---|---|---|---|
...props |
InputHTMLAttributes |
— | All standard input props. |
className |
string |
— | Additional CSS classes. |
FloatingLabel.Label
Section titled “FloatingLabel.Label”| Prop | Type | Default | Description |
|---|---|---|---|
htmlFor |
string |
— | Matches the input id. |
children |
React.ReactNode |
— | The label text. |
className |
string |
— | Additional CSS classes. |
Theme styles
Section titled “Theme styles”The Floating Label Input ships in a dedicated variant for each supported shadcn style. Installed through the @prisma namespace, the CLI delivers the one matching the style in your components.json — same API, with the input sizing and label offsets adjusted per style:
See Styles & Themes for setup and the full list of supported styles.