Animated sections
Animated FAQ
Questions whose answers open smoothly in place, with the plus turning into a cross.
native details · height animation · answer fade · rotating icon · first open
Questions, answered
Can’t find yours? Write to us — a person replies within a working day.
Do my clients need an account to pay?
No. Each invoice has a pay link. Your client opens it, pays by card or bank transfer, and gets a receipt by email.
What do you charge on payments?
Only the payment processor’s fee, shown before you send. Nothing is added on top.
Can I bill in another currency?
Yes. Pick any of 24 currencies per invoice. Totals on your dashboard stay in your home currency.
Can I change or cancel my plan?
Any time, from Settings. If you cancel, you keep access until the end of the period you’ve paid for.
Who can see my invoices?
Only you, the people you invite and the client each invoice is addressed to.
import { Plus } from "lucide-react";
/* Add once to globals.css:
@keyframes answer-in { from { opacity: 0; transform: translateY(-6px); } }
Height animates in browsers that support ::details-content and
interpolate-size; elsewhere the answer simply opens. */
const faqs = [
{ q: "Do my clients need an account to pay?", a: "No. Each invoice has a pay link. Your client opens it, pays by card or bank transfer, and gets a receipt by email." },
{ q: "What do you charge on payments?", a: "Only the payment processor’s fee, shown before you send. Nothing is added on top." },
{ q: "Can I bill in another currency?", a: "Yes. Pick any of 24 currencies per invoice. Totals on your dashboard stay in your home currency." },
{ q: "Can I change or cancel my plan?", a: "Any time, from Settings. If you cancel, you keep access until the end of the period you’ve paid for." },
{ q: "Who can see my invoices?", a: "Only you, the people you invite and the client each invoice is addressed to." },
];
export function AnimatedFaq() {
return (
<section aria-labelledby="faq-title" className="bg-bg py-20 font-sans">
<div className="mx-auto grid max-w-6xl gap-10 px-4 sm:px-6 lg:grid-cols-[.8fr_1.4fr] lg:gap-16 [interpolate-size:allow-keywords]">
<div>
<h2 id="faq-title" className="text-3xl font-medium tracking-tight text-fg">Questions, answered</h2>
<p className="mt-3 text-sm leading-relaxed text-fg-muted">
Can’t find yours? <a href="/contact" className="text-primary underline underline-offset-4">Write to us</a> — a person replies within a working day.
</p>
</div>
<div className="border-t border-border">
{faqs.map((f, i) => (
<details
key={f.q}
open={i === 0}
className="group border-b border-border [&::details-content]:h-0 [&::details-content]:overflow-hidden [&::details-content]:[transition:height_.4s_cubic-bezier(.2,.7,.1,1),content-visibility_.4s_allow-discrete] [&[open]::details-content]:h-auto motion-reduce:[&::details-content]:transition-none animate-rise motion-reduce:animate-none"
style={{ animationDelay: 150 + i * 70 + "ms" }}
>
<summary className="flex cursor-pointer list-none items-center justify-between gap-4 py-4 text-[15px] font-medium text-fg transition-colors hover:text-primary [&::-webkit-details-marker]:hidden">
{f.q}
<Plus className="size-4 shrink-0 text-fg-subtle transition duration-[400ms] ease-spring group-open:rotate-45 group-open:text-primary motion-reduce:transition-none" aria-hidden />
</summary>
<p className="pb-5 pr-8 text-sm leading-relaxed text-fg-muted group-open:animate-[answer-in_.45s_cubic-bezier(.2,.7,.1,1)_both] motion-reduce:animate-none">{f.a}</p>
</details>
))}
</div>
</div>
</section>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.