Components
A text input whose label animates up into a reserved slot above the field instead of disappearing, with focus/invalid states, an optional hint line and a character counter.

"use client";
import * as React from "react";
import { FloatingLabelInput } from "@/components/ui/floating-label";
export default function BillingContact() {
const [email, setEmail] = React.useState("");
const [reference, setReference] = React.useState("");
const [touched, setTouched] = React.useState(false);
const bad = touched && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
return (
<div className="flex justify-center">
<form className="grid w-full max-w-[320px] gap-4">
<FloatingLabelInput
label="Work email"
type="email"
autoComplete="email"
required
value={email}
onChange={setEmail}
onBlur={() => setTouched(true)}
invalid={bad}
hint={
bad
? "Needs to look like name@company.com"
: "Receipts are sent here."
}
/>
<FloatingLabelInput
label="Invoice reference"
value={reference}
onChange={setReference}
maxLength={16}
hint="Printed on the statement header."
/>
</form>
</div>
);
}

Part of interior.dev — browse the full library on 21st.dev.