All Taste components
Animated heroes
Hero — split with signup form (motion)
The form card slides in from the right with its fields arriving one after another, and the first field lights up as if focused.
copy rises · card slide · fields stagger in · tick pops · one focus glow
Free for your first 5 invoices
Your next invoice could be out in two minutes.
Make an account, add a client and send a branded invoice with a pay link — before your coffee's cold.
- Card and bank transfer on every invoice
- Reminders that stop the moment you’re paid
- Export everything for your accountant
import { Check } from "lucide-react";
/* Add once to globals.css:
@keyframes slide-in-right { from { opacity: 0; translate: 28px 0; } }
@keyframes focus-glow { 25%, 60% { border-color: var(--tst-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--tst-primary) 22%, transparent); } }
*/
const points = [
"Card and bank transfer on every invoice",
"Reminders that stop the moment you’re paid",
"Export everything for your accountant",
];
const clientCounts = [
{ value: "1", label: "Just one" },
{ value: "2-10", label: "2 – 10" },
{ value: "11+", label: "More than 10" },
];
const field = "h-10 w-full rounded border border-border-strong bg-bg px-3 text-sm text-fg placeholder:text-fg-subtle focus:border-primary focus:outline-none focus:ring-4 focus:ring-ring/20";
// Each form row slides in from the right, one after another.
const slideIn = "animate-[slide-in-right_.6s_cubic-bezier(.2,.7,.1,1)_both] motion-reduce:animate-fade";
const at = (i: number) => ({ animationDelay: 500 + i * 110 + "ms" });
export function HeroSignupFormMotion({ action = "/api/signup" }: { action?: string }) {
return (
<section aria-labelledby="hero-title" className="bg-bg bg-gradient-to-b from-bg from-55% to-primary-soft/40 font-sans">
<div className="mx-auto grid max-w-6xl items-center gap-10 px-4 py-16 sm:px-6 sm:py-24 lg:grid-cols-[1.15fr_0.85fr] lg:gap-14">
<div className="flex flex-col items-start gap-5">
<p className="text-[13px] font-medium text-primary animate-rise motion-reduce:animate-fade">Free for your first 5 invoices</p>
<h1 id="hero-title" className="text-balance text-4xl font-semibold leading-[1.04] tracking-tight text-fg animate-rise [animation-delay:90ms] motion-reduce:animate-fade sm:text-5xl lg:text-6xl">
Your next invoice could be out in two minutes.
</h1>
<p className="max-w-lg text-pretty text-base leading-relaxed text-fg-muted animate-rise [animation-delay:180ms] motion-reduce:animate-fade sm:text-lg">
Make an account, add a client and send a branded invoice with a pay link — before your coffee’s cold.
</p>
<ul className="grid gap-2.5 text-sm text-fg">
{points.map((p, i) => (
<li key={p} className="flex gap-2.5 animate-rise motion-reduce:animate-fade" style={{ animationDelay: 350 + i * 90 + "ms" }}>
<Check className="mt-0.5 size-4 shrink-0 text-primary animate-pop motion-reduce:animate-fade" style={{ animationDelay: 700 + i * 140 + "ms" }} aria-hidden />{p}
</li>
))}
</ul>
</div>
<form action={action} method="post" aria-labelledby="signup-title" className="grid gap-3.5 rounded-xl border border-border bg-bg p-5 shadow-2xl animate-[slide-in-right_.85s_cubic-bezier(.2,.7,.1,1)_.2s_both] motion-reduce:animate-fade sm:p-7">
<h2 id="signup-title" className={"text-lg font-semibold tracking-tight text-fg " + slideIn} style={at(0)}>Create your free account</h2>
<label className={"grid gap-1.5 " + slideIn} style={at(1)}>
<span className="text-[13px] font-medium text-fg">Your name</span>
<input name="name" required autoComplete="name" placeholder="Asha Rao" className={field + " animate-[focus-glow_1.4s_cubic-bezier(.2,.7,.1,1)_1.35s_both] motion-reduce:animate-none"} />
</label>
<label className={"grid gap-1.5 " + slideIn} style={at(2)}>
<span className="text-[13px] font-medium text-fg">Work email</span>
<input name="email" type="email" required autoComplete="email" placeholder="asha@studio.com" className={field} />
</label>
<label className={"grid gap-1.5 " + slideIn} style={at(3)}>
<span className="text-[13px] font-medium text-fg">How many clients do you bill?</span>
<select name="clients" defaultValue="2-10" className={field}>
{clientCounts.map((c) => <option key={c.value} value={c.value}>{c.label}</option>)}
</select>
</label>
<button type="submit" className={"h-[42px] rounded bg-primary text-sm font-medium text-primary-fg transition hover:bg-primary-hover " + slideIn} style={at(4)}>Create account</button>
<p className={"text-xs leading-relaxed text-fg-subtle " + slideIn} style={at(5)}>
By signing up you agree to the <a href="/terms" className="text-fg-muted underline">Terms</a> and{" "}
<a href="/privacy" className="text-fg-muted underline">Privacy Policy</a>. No card needed.
</p>
</form>
</div>
</section>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.