Floating Input
Astro text fields with a label that moves when focused or filled.
---
import { FloatingInput } from "@/components/ui/floating-input"
---
<div class="flex w-full max-w-sm flex-col gap-6 py-2">
<FloatingInput id="floating-email" name="email" type="email" label="Email" />
<FloatingInput
id="floating-name"
name="name"
type="text"
label="Name"
value="Ada Lovelace"
/>
</div>
Installation
bunx --bun shadcn@latest add @gnosticai/floating-input
The command also installs Input, Textarea, and Label.
Usage
import { FloatingInput } from "@/components/ui/floating-input"
<FloatingInput id="email" name="email" type="email" label="Email" />
Set id. The label uses that id. Omit placeholder when the label is the
only hint. The component then uses a space, and that placeholder stays invisible.
Size
md is the default. size="sm" makes the field shorter.
---
import { FloatingInput } from "@/components/ui/floating-input"
---
<div class="w-full max-w-sm py-2">
<FloatingInput
id="floating-phone"
name="phone"
type="tel"
label="Phone"
size="sm"
/>
</div>
Description and error
description adds helper text. error adds a validation message and marks
the control invalid.
---
import { FloatingInput } from "@/components/ui/floating-input"
---
<div class="w-full max-w-sm py-2">
<FloatingInput
id="floating-username"
name="username"
type="text"
label="Username"
description="This name is public."
error="Enter a username."
/>
</div>
Textarea
FloatingTextarea uses the same label. The empty label sits on the first line.
---
import { FloatingTextarea } from "@/components/ui/floating-input"
---
<div class="w-full max-w-sm py-2">
<FloatingTextarea
id="floating-message"
name="message"
label="Message"
rows={4}
/>
</div>
Input and label classes
Use the slot classes when you build the field from Input and Label.
Place the label after the input. Keep helper text outside that wrapper.
The empty label uses half the height of the wrapper.
---
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
floatingInputRootClass,
floatingInputVariants,
floatingLabelVariants,
} from "@/components/ui/floating-input"
---
<div class={floatingInputRootClass}>
<Input id="city" class={floatingInputVariants()} placeholder=" " />
<Label class={floatingLabelVariants()} for="city">City</Label>
</div>
---
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import {
floatingInputRootClass,
floatingInputVariants,
floatingLabelVariants,
} from "@/components/ui/floating-input"
---
<div class="w-full max-w-sm py-2">
<div class={floatingInputRootClass}>
<Input
id="floating-city"
name="city"
class={floatingInputVariants()}
placeholder=" "
/>
<Label class={floatingLabelVariants()} for="floating-city">
City
</Label>
</div>
</div>
Notes
classstyles the wrapper. Use it for width.sizesets the field height. It acceptssmandmd.- The label follows the control so the empty, focus, and filled states work.
- Pass
errorto show a message and setaria-invalid. - Pass
descriptionfor helper text. The control references that text.
API Reference
Read the installed source for the complete prop types.
When to use Floating Input
Provide both id and label. FloatingInput composes an Input and a linked label, with optional description and error text. The placeholder supports the floating-label layout; it is not the accessible name.
Keyboard and behavior
The native input keeps normal keyboard and form behavior. Keep the visible label clear even after typing. Error text should explain the correction and remain associated with the field.
Theme and layout
Test browser autofill, long labels, and zoom with the selected size. The floating label sits over the field surface, so custom backgrounds must match the surrounding input design.
Related choices
Use Input and Field when a fixed label above the control is clearer.