Card Examples
A collection of Tailwind CSS card examples with beautiful shadcn/ui styling. Use them for things like login forms, user profiles, pricing, and dashboard widgets, or as inspiration for your own designs. Every example is built on the card component and ready to copy into your project.
Login
A login form with a forgot password link and social sign in.
<div class="card">
<div class="card-header">
<h3 class="card-title">Sign In</h3>
<p class="card-description">
Enter your credentials to access your account.
</p>
</div>
<div class="card-content field-group">
<form class="field-group">
<div class="field">
<label class="label" for="signin-email">Email</label
><input
class="input"
id="signin-email"
type="email"
placeholder="[email protected]"
name="email"
/>
</div>
<div class="field">
<div class="flex w-full items-center">
<label class="label" for="signin-password">Password</label
><a
href="#"
class="ml-auto text-sm underline-offset-4 hover:underline"
>Forgot password?</a
>
</div>
<input
class="input"
id="signin-password"
type="password"
name="password"
/>
</div>
<button class="btn" type="submit">Sign In</button>
</form>
<div class="field-separator">
<span class="text-xs uppercase">Or continue with</span>
</div>
<div class="grid grid-cols-2 gap-5">
<button class="btn btn-outline" type="button">
<svg
class="icon-start"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
></path></svg
>Google</button
><button class="btn btn-outline" type="button">
<svg
class="icon-start"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
></path></svg
>GitHub
</button>
</div>
</div>
<div class="card-footer justify-center">
<p class="text-sm text-muted-foreground">
Don't have an account?
<a
href="#"
class="font-medium text-foreground underline underline-offset-4"
>Sign up</a
>
</p>
</div>
</div>Sign Up
A sign up form with email and password fields and social providers.
<div class="card">
<div class="card-header">
<h3 class="card-title">Sign Up</h3>
<p class="card-description">
Create an account to get started on the platform and unlock all features
and benefits.
</p>
</div>
<div class="card-content field-group">
<div class="grid grid-cols-2 gap-5">
<button class="btn btn-outline" type="button">
<svg
class="icon-start"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"
></path></svg
>Google</button
><button class="btn btn-outline" type="button">
<svg
class="icon-start"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
>
<path
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
></path></svg
>GitHub
</button>
</div>
<div class="field-separator">
<span class="text-xs uppercase">Or continue with</span>
</div>
<form class="field-group">
<div class="field">
<label class="label" for="signup-email">Email</label
><input
class="input"
id="signup-email"
type="email"
placeholder="[email protected]"
name="email"
/>
</div>
<div class="field">
<label class="label" for="signup-password">Password</label
><input
class="input"
id="signup-password"
type="password"
name="password"
/>
</div>
<button class="btn" type="submit">Create Account</button>
</form>
</div>
<div class="card-footer justify-center">
<p class="text-sm text-muted-foreground">
Already have an account?
<a
href="#"
class="font-medium text-foreground underline underline-offset-4"
>Sign in</a
>
</p>
</div>
</div>Product
A product card with a cover photo, rating, price, and add to cart action.
<div class="card relative">
<img
src="https://images.unsplash.com/photo-1578500494198-246f612d3b3d?rect=0,0,4896,3264&w=640&h=427&fit=crop&auto=format&q=100"
alt="Vintage leather sofa"
class="aspect-3/2 w-full object-cover"
/><span class="badge absolute top-3 left-3">Sale</span>
<div class="card-header">
<span class="text-xs font-medium tracking-tight text-muted-foreground"
>Furniture</span
>
<h3 class="card-title">Vintage Leather Sofa</h3>
<p class="card-description">
Full-grain aniline leather sofa with a sturdy oak hardwood frame and a
soft, lived-in feel.
</p>
</div>
<div class="card-content flex items-center gap-2">
<div class="flex gap-1">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-muted"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path>
</svg>
</div>
<span class="text-sm text-muted-foreground">(128)</span>
</div>
<div class="card-footer justify-between">
<div class="flex items-baseline gap-2">
<span class="text-lg font-bold">$899</span
><span class="text-sm text-muted-foreground line-through">$1,099</span>
</div>
<button class="btn btn-sm">
Add to Cart<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-plus icon-end"
aria-hidden="true"
>
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg>
</button>
</div>
</div>Blog Post
An article preview with a cover image, title, and author.
<div class="card">
<img
src="https://images.unsplash.com/photo-1592765213254-f101ad9b8f76?rect=0,0,3000,2000&w=640&h=427&fit=crop&auto=format&q=100"
alt="White blossoms in muted warm tones"
class="aspect-3/2 w-full object-cover"
/>
<div class="card-header">
<span
class="flex items-center gap-1.5 text-xs font-medium tracking-tight text-muted-foreground"
><span>Mar 15, 2024</span><span>·</span><span>Design</span></span
>
<h3 class="card-title">Finding Color Palettes in Nature</h3>
<p class="card-description">
How muted, organic tones from the natural world can ground the color
system of your next project.
</p>
</div>
<div class="card-footer gap-3">
<span class="avatar avatar-lg"
><img
class="avatar-image"
src="https://images.unsplash.com/photo-1750390200282-bf7f669a9946?w=640&h=640&fit=facearea&facepad=3.2&auto=format&q=100&bg-remove=true&bg=e5e5e5"
alt="Leila Navarro"
/><span class="avatar-fallback">LN</span></span
>
<div class="text-sm">
<p class="font-medium text-foreground">Leila Navarro</p>
<p class="text-muted-foreground">Product Designer</p>
</div>
</div>
</div>Share Document
A share dialog with a copyable link and per-person access levels.
<div class="card">
<div class="card-header">
<h3 class="card-title">Share Document</h3>
<p class="card-description">
Invite others to view or edit this document and work together seamlessly.
</p>
</div>
<div class="card-content flex flex-col gap-6">
<div class="flex gap-2">
<input
class="input flex-1"
type="text"
readonly=""
aria-label="Document link"
value="https://example.com/doc/abc123"
/><button class="btn btn-outline btn-icon" aria-label="Copy link">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-copy"
aria-hidden="true"
>
<rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
<path
d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"
></path>
</svg>
</button>
</div>
<div class="separator"></div>
<span class="text-sm font-medium">People with access</span>
<div class="flex items-center justify-between gap-4">
<div class="flex items-center gap-3">
<span class="avatar avatar-lg"
><img
class="avatar-image"
src="https://images.unsplash.com/photo-1750390200282-bf7f669a9946?w=640&h=640&fit=facearea&facepad=3.2&auto=format&q=100&bg-remove=true&bg=e5e5e5"
alt="Leila Navarro"
/><span class="avatar-fallback">LN</span></span
>
<div class="text-sm">
<p class="font-medium text-foreground">Leila Navarro</p>
<p class="text-muted-foreground">[email protected]</p>
</div>
</div>
<select class="select h-8 w-22" aria-label="Permission for Leila Navarro">
<option value="write">Write</option>
<option value="read">Read</option>
</select>
</div>
<div class="flex items-center justify-between gap-4">
<div class="flex items-center gap-3">
<span class="avatar avatar-lg"
><img
class="avatar-image"
src="https://images.unsplash.com/photo-1750390200293-92d5a788d3a2?w=640&h=640&fit=facearea&facepad=3&auto=format&q=100&bg-remove=true&bg=e5e5e5"
alt="Theo Marchetti"
/><span class="avatar-fallback">TM</span></span
>
<div class="text-sm">
<p class="font-medium text-foreground">Theo Marchetti</p>
<p class="text-muted-foreground">[email protected]</p>
</div>
</div>
<select
class="select h-8 w-22"
aria-label="Permission for Theo Marchetti"
>
<option value="read">Read</option>
<option value="write">Write</option>
</select>
</div>
<div class="flex items-center justify-between gap-4">
<div class="flex items-center gap-3">
<span class="avatar avatar-lg"
><img
class="avatar-image"
src="https://images.unsplash.com/photo-1573497019236-17f8177b81e8?w=640&h=640&fit=facearea&facepad=3.2&auto=format&q=100&bg-remove=true&bg=e5e5e5"
alt="Maya Santoso"
/><span class="avatar-fallback">MS</span></span
>
<div class="text-sm">
<p class="font-medium text-foreground">Camille Laurent</p>
<p class="text-muted-foreground">[email protected]</p>
</div>
</div>
<select
class="select h-8 w-22"
aria-label="Permission for Camille Laurent"
>
<option value="read">Read</option>
<option value="write">Write</option>
</select>
</div>
</div>
</div>Payment Method
A payment method picker built from radio choice cards.
<div class="card">
<div class="card-header">
<h3 class="card-title">Payment Method</h3>
<p class="card-description">
Choose how you'd like to pay for your order.
</p>
</div>
<div
class="card-content grid grid-cols-3 gap-3"
role="radiogroup"
aria-label="Payment method"
>
<label class="label"
><div class="field items-center gap-2 text-center">
<input
type="radio"
class="sr-only"
name="payment"
checked=""
value="card"
/><svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="size-6"
>
<path
d="M11.343 18.031c.058.049.12.098.181.146-1.177.783-2.59 1.238-4.107 1.238C3.32 19.416 0 16.096 0 12c0-4.095 3.32-7.416 7.416-7.416 1.518 0 2.931.456 4.105 1.238-.06.051-.12.098-.165.15C9.6 7.489 8.595 9.688 8.595 12c0 2.311 1.001 4.51 2.748 6.031zm5.241-13.447c-1.52 0-2.931.456-4.105 1.238.06.051.12.098.165.15C14.4 7.489 15.405 9.688 15.405 12c0 2.31-1.001 4.507-2.748 6.031-.058.049-.12.098-.181.146 1.177.783 2.588 1.238 4.107 1.238C20.68 19.416 24 16.096 24 12c0-4.094-3.32-7.416-7.416-7.416zM12 6.174c-.096.075-.189.15-.28.231C10.156 7.764 9.169 9.765 9.169 12c0 2.236.987 4.236 2.551 5.595.09.08.185.158.28.232.096-.074.189-.152.28-.232 1.563-1.359 2.551-3.359 2.551-5.595 0-2.235-.987-4.236-2.551-5.595-.09-.08-.184-.156-.28-.231z"
></path></svg
><span class="text-sm font-medium">Card</span>
</div></label
><label class="label"
><div class="field items-center gap-2 text-center">
<input type="radio" class="sr-only" name="payment" value="paypal" /><svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="size-6"
>
<path
d="M15.607 4.653H8.941L6.645 19.251H1.82L4.862 0h7.995c3.754 0 6.375 2.294 6.473 5.513-.648-.478-2.105-.86-3.722-.86m6.57 5.546c0 3.41-3.01 6.853-6.958 6.853h-2.493L11.595 24H6.74l1.845-11.538h3.592c4.208 0 7.346-3.634 7.153-6.949a5.24 5.24 0 0 1 2.848 4.686M9.653 5.546h6.408c.907 0 1.942.222 2.363.541-.195 2.741-2.655 5.483-6.441 5.483H8.714Z"
></path></svg
><span class="text-sm font-medium">PayPal</span>
</div></label
><label class="label"
><div class="field items-center gap-2 text-center">
<input type="radio" class="sr-only" name="payment" value="apple" /><svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
class="size-6"
>
<path
d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701"
></path></svg
><span class="text-sm font-medium">Apple</span>
</div></label
>
</div>
<form class="card-content field-group">
<div class="field">
<label class="label" for="pay-name">Cardholder Name</label
><input
class="input"
id="pay-name"
type="text"
placeholder="John Doe"
name="cardholder-name"
/>
</div>
<div class="field">
<label class="label" for="pay-number">Card Number</label
><input
class="input"
id="pay-number"
type="text"
placeholder="1234 5678 9012 3456"
name="card-number"
/>
</div>
<div class="grid grid-cols-3 gap-4">
<div class="field">
<label class="label" for="pay-month">Month</label
><input
class="input"
id="pay-month"
type="text"
placeholder="MM"
name="month"
/>
</div>
<div class="field">
<label class="label" for="pay-year">Year</label
><input
class="input"
id="pay-year"
type="text"
placeholder="YY"
name="year"
/>
</div>
<div class="field">
<label class="label" for="pay-cvv">CVV</label
><input
class="input"
id="pay-cvv"
type="text"
placeholder="123"
name="cvv"
/>
</div>
</div>
<button class="btn" type="submit">Continue</button>
</form>
</div>Notifications
Notification preferences with descriptive switch rows.
<div class="card">
<div class="card-header">
<h3 class="card-title">Notifications</h3>
<p class="card-description">Choose how you want to be notified.</p>
</div>
<div class="card-content field-group gap-5">
<div class="field field-horizontal">
<div class="field-content">
<label class="label" for="notif-email">Email notifications</label>
<p class="field-description">Receive updates and alerts via email.</p>
</div>
<input
type="checkbox"
role="switch"
class="switch"
id="notif-email"
name="notif-email"
checked=""
/>
</div>
<div class="field field-horizontal">
<div class="field-content">
<label class="label" for="notif-push">Push notifications</label>
<p class="field-description">
Get instant alerts on your mobile device.
</p>
</div>
<input
type="checkbox"
role="switch"
class="switch"
id="notif-push"
name="notif-push"
/>
</div>
<div class="field field-horizontal">
<div class="field-content">
<label class="label" for="notif-marketing">Marketing emails</label>
<p class="field-description">
Stay informed about new features and offers.
</p>
</div>
<input
type="checkbox"
role="switch"
class="switch"
id="notif-marketing"
name="notif-marketing"
/>
</div>
</div>
<div class="card-footer">
<button class="btn w-full">Save preferences</button>
</div>
</div>Feedback
A feedback form with a type select, title input, and message textarea.
<div class="card">
<div class="card-header">
<h3 class="card-title">Submit Feedback</h3>
<p class="card-description">Share your thoughts to help us improve.</p>
</div>
<form class="card-content field-group">
<div class="field">
<label class="label" for="fb-title">Title</label
><input
class="input"
id="fb-title"
type="text"
placeholder="Feedback title"
name="title"
/>
</div>
<div class="field">
<label class="label" for="fb-type">Type</label
><select class="select" id="fb-type" name="type">
<option value="">Select type</option>
<option value="suggestion">Suggestion</option>
<option value="complaint">Complaint</option>
<option value="praise">Praise</option>
</select>
</div>
<div class="field">
<label class="label" for="fb-description">Description</label
><textarea
class="textarea"
id="fb-description"
name="description"
placeholder="Tell us more..."
></textarea>
</div>
<div class="flex justify-end gap-2">
<button class="btn btn-outline" type="button">Cancel</button
><button class="btn" type="submit">Submit</button>
</div>
</form>
</div>Premium Plan
A pricing card with a feature list and upgrade action.
<div class="card">
<div class="card-header"><h3 class="card-title">Premium Plan</h3></div>
<div class="card-content flex flex-col gap-6">
<div>
<span class="text-4xl font-bold sm:text-5xl">$29</span
><span class="ml-1 text-muted-foreground">/ month</span>
</div>
<p class="text-sm/6 text-muted-foreground">
Everything you need to scale your project and collaborate with your entire
team.
</p>
<div class="separator"></div>
<ul class="grid gap-4 text-sm">
<li class="flex items-center text-muted-foreground">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check mr-4 size-4 text-primary"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path></svg
><span>Up to 10 team members</span>
</li>
<li class="flex items-center text-muted-foreground">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check mr-4 size-4 text-primary"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path></svg
><span>50GB cloud storage</span>
</li>
<li class="flex items-center text-muted-foreground">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check mr-4 size-4 text-primary"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path></svg
><span>Priority email support</span>
</li>
<li class="flex items-center text-muted-foreground">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check mr-4 size-4 text-primary"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path></svg
><span>Advanced analytics dashboard</span>
</li>
<li class="flex items-center text-muted-foreground">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check mr-4 size-4 text-primary"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path></svg
><span>API access</span>
</li>
</ul>
</div>
<div class="card-footer">
<button class="btn btn-lg w-full">Buy Now</button>
</div>
</div>Profile
A profile card with a photo, bio, follower stats, and a follow action.
<div class="card">
<div class="card-content">
<img
src="https://images.unsplash.com/photo-1604573824303-d0177f69461f?rect=0,0,4000,4000&w=640&h=640&fit=crop&auto=format&q=100"
alt="Vivienne Kleinfeld"
class="aspect-square w-full rounded-xl object-cover"
/>
</div>
<div class="card-header">
<h3 class="card-title">Vivienne Kleinfeld</h3>
<p class="card-description">
Product Designer who focuses on simplicity & usability. Currently
designing at Acme Inc.
</p>
</div>
<div class="card-footer gap-6">
<div class="leading-tight">
<p class="text-sm font-semibold tabular-nums">312</p>
<p class="text-xs text-muted-foreground">Followers</p>
</div>
<div class="leading-tight">
<p class="text-sm font-semibold tabular-nums">48</p>
<p class="text-xs text-muted-foreground">Following</p>
</div>
<button class="btn btn-sm ml-auto">
Follow<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-plus icon-end"
aria-hidden="true"
>
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg>
</button>
</div>
</div>Testimonial
A testimonial with a star rating and reviewer details.
<div class="card">
<div class="card-content flex flex-col gap-6">
<div class="flex gap-1">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path></svg
><svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-star size-4.5 text-primary"
aria-hidden="true"
>
<path
d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z"
></path>
</svg>
</div>
<p class="text-sm/6 text-muted-foreground">
Starting Point UI has transformed how we build interfaces. The components
are beautifully designed and easy to customize.
</p>
</div>
<div class="card-footer gap-3">
<span class="avatar avatar-lg"
><img
class="avatar-image"
src="https://images.unsplash.com/photo-1750390200282-bf7f669a9946?w=640&h=640&fit=facearea&facepad=3.2&auto=format&q=100&bg-remove=true&bg=e5e5e5"
alt="Leila Navarro"
/><span class="avatar-fallback">LN</span></span
>
<div class="text-sm">
<p class="font-medium text-foreground">Leila Navarro</p>
<p class="text-muted-foreground">Product Designer</p>
</div>
</div>
</div>Music Player
A now playing card with track progress and transport controls.
<div class="card">
<img
src="https://images.unsplash.com/photo-1605084198811-7a358b91dc15?rect=0,0,4000,4000&w=640&h=640&fit=crop&auto=format&q=100"
alt="Album cover"
class="aspect-square w-full object-cover"
/>
<div class="card-header text-center">
<h3 class="card-title">Midnight Dreams</h3>
<p class="card-description">Luna Eclipse</p>
</div>
<div class="card-content grid gap-2">
<progress
class="progress"
value="83"
max="225"
aria-label="Playback position"
></progress>
<div class="flex justify-between text-xs text-muted-foreground">
<span>1:23</span><span>3:45</span>
</div>
</div>
<div class="card-footer justify-center gap-4">
<button class="btn btn-ghost btn-icon" aria-label="Shuffle">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-shuffle"
aria-hidden="true"
>
<path d="m18 14 4 4-4 4"></path>
<path d="m18 2 4 4-4 4"></path>
<path
d="M2 18h1.973a4 4 0 0 0 3.3-1.7l5.454-8.6a4 4 0 0 1 3.3-1.7H22"
></path>
<path d="M2 6h1.972a4 4 0 0 1 3.6 2.2"></path>
<path d="M22 18h-6.041a4 4 0 0 1-3.3-1.8l-.359-.45"></path>
</svg></button
><button class="btn btn-ghost btn-icon" aria-label="Previous track">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-skip-back"
aria-hidden="true"
>
<path
d="M17.971 4.285A2 2 0 0 1 21 6v12a2 2 0 0 1-3.029 1.715l-9.997-5.998a2 2 0 0 1-.003-3.432z"
></path>
<path d="M3 20V4"></path>
</svg></button
><button class="btn btn-icon rounded-full" aria-label="Pause">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-pause"
aria-hidden="true"
>
<rect x="14" y="3" width="5" height="18" rx="1"></rect>
<rect x="5" y="3" width="5" height="18" rx="1"></rect>
</svg></button
><button class="btn btn-ghost btn-icon" aria-label="Next track">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="currentColor"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-skip-forward"
aria-hidden="true"
>
<path d="M21 4v16"></path>
<path
d="M6.029 4.285A2 2 0 0 0 3 6v12a2 2 0 0 0 3.029 1.715l9.997-5.998a2 2 0 0 0 .003-3.432z"
></path>
</svg></button
><button class="btn btn-ghost btn-icon" aria-label="Repeat">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-repeat"
aria-hidden="true"
>
<path d="m17 2 4 4-4 4"></path>
<path d="M3 11v-1a4 4 0 0 1 4-4h14"></path>
<path d="m7 22-4-4 4-4"></path>
<path d="M21 13v1a4 4 0 0 1-4 4H3"></path>
</svg>
</button>
</div>
</div>Chat
An assistant chat with streaming replies, built on the message scroller.
<div class="card h-140 w-full max-w-sm gap-0">
<div class="card-header border-b">
<div class="card-title">New Chat</div>
<div class="card-description">How can I help you today?</div>
<div class="card-action">
<button
id="chat-reset"
class="btn btn-outline btn-icon"
aria-label="Reset conversation"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8"></path>
<path d="M21 3v5h-5"></path>
</svg>
</button>
<div class="tooltip" data-sp-toggle="#chat-reset">Reset</div>
</div>
</div>
<div class="card-content flex-1 overflow-hidden p-0">
<div class="empty h-full" id="chat-empty">
<div class="empty-header">
<div class="empty-media empty-media-icon">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M10.1 2.182a10 10 0 0 1 3.8 0"></path>
<path d="M13.9 21.818a10 10 0 0 1-3.8 0"></path>
<path d="M17.609 3.72a10 10 0 0 1 2.69 2.7"></path>
<path d="M2.182 13.9a10 10 0 0 1 0-3.8"></path>
<path d="M20.28 17.61a10 10 0 0 1-2.7 2.69"></path>
<path d="M21.818 10.1a10 10 0 0 1 0 3.8"></path>
<path d="M3.721 6.391a10 10 0 0 1 2.7-2.69"></path>
<path
d="m6.163 21.117-2.906.85a1 1 0 0 1-1.236-1.169l.965-2.98"
></path>
</svg>
</div>
<div class="empty-title">Morning, John!</div>
<div class="empty-description">
What are we working on today? Type a message to start the conversation
</div>
</div>
</div>
<div
class="message-scroller hidden size-full"
id="chat-scroller"
data-sp-auto-scroll="true"
>
<div class="message-scroller-viewport">
<div class="message-scroller-content p-6" id="chat-content"></div>
</div>
<button
class="message-scroller-button btn btn-sm btn-icon"
aria-label="Scroll to latest"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M12 5v14"></path>
<path d="m19 12-7 7-7-7"></path>
</svg>
</button>
</div>
</div>
<div class="card-footer">
<form class="w-full" id="chat-form">
<div class="input-group">
<textarea
class="textarea scrollbar scrollbar-sm max-h-32 min-h-0"
id="chat-input"
placeholder="Ask about the scroll behavior..."
autocomplete="off"
></textarea>
<div class="input-group-addon input-group-addon-block-end pt-1">
<button
id="chat-plus"
class="btn btn-outline btn-sm btn-icon"
type="button"
aria-label="Add files"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg></button
><button
id="chat-send"
class="btn btn-sm btn-icon ms-auto"
type="submit"
aria-label="Send"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m5 12 7-7 7 7"></path>
<path d="M12 19V5"></path>
</svg>
</button>
</div>
</div>
</form>
<div
class="dropdown w-44"
data-sp-toggle="#chat-plus"
data-sp-placement="top-start"
>
<button class="dropdown-item">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551"
></path></svg
>Add Photos & Files
</button>
<div class="dropdown-separator"></div>
<button class="dropdown-item">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect>
<circle cx="9" cy="9" r="2"></circle>
<path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"></path></svg
>Create Image</button
><button class="dropdown-item">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="m10.065 12.493-6.18 1.318a.934.934 0 0 1-1.108-.702l-.537-2.15a1.07 1.07 0 0 1 .691-1.265l13.504-4.44"
></path>
<path d="m13.56 11.747 4.332-.924"></path>
<path d="m16 21-3.105-6.21"></path>
<path
d="M16.485 5.94a2 2 0 0 1 1.455-2.425l1.09-.272a1 1 0 0 1 1.212.727l1.515 6.06a1 1 0 0 1-.727 1.213l-1.09.272a2 2 0 0 1-2.425-1.455z"
></path>
<path d="m6.158 8.633 1.114 4.456"></path>
<path d="m8 21 3.105-6.21"></path>
<circle cx="12" cy="13" r="2"></circle></svg
>Deep Research</button
><button class="dropdown-item">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="10"></circle>
<path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"></path>
<path d="M2 12h20"></path></svg
>Web Search
</button>
</div>
</div>
<script>
const chatContent = document.querySelector("#chat-content");
const chatForm = document.querySelector("#chat-form");
const chatInput = document.querySelector("#chat-input");
const chatReset = document.querySelector("#chat-reset");
const chatSend = document.querySelector("#chat-send");
const chatEmpty = document.querySelector("#chat-empty");
const chatScroller = document.querySelector("#chat-scroller");
const userMessage = (text) => {
const el = document.createElement("div");
el.className = "message-scroller-item";
el.setAttribute("data-sp-anchor", "");
el.innerHTML =
'<div class="message message-end"><div class="message-content"><div class="bubble bubble-muted"><div class="bubble-content"></div></div></div></div>';
el.querySelector(".bubble-content").textContent = text;
return el;
};
const assistantMessage = () => {
const el = document.createElement("div");
el.className = "message-scroller-item";
el.innerHTML =
'<div class="message"><div class="message-content"><div class="bubble bubble-ghost"><div class="bubble-content space-y-2"></div></div></div></div>';
return el;
};
const firstReply = [
"That's the classic streaming scroll problem. Wrap your message list in a message scroller and turn on auto-scroll: the viewport pins to the bottom as tokens arrive, so users always see the latest text land in place.",
"The important part: it only auto-scrolls while the reader is already at the bottom. The moment they scroll up to read something earlier, auto-scroll backs off and their position is preserved. You get smooth streaming without fighting the user's intent.",
];
const chatReplies = [
"New messages keep the thread steady too. Your question just pinned to the top as a turn, and this reply is streaming in below it.",
"If you scroll up right now, the view stays put. The floating arrow appears so you can jump back down whenever you are ready.",
"Loading older history works the same way: rows prepended above the viewport never move what you are reading.",
"All of this is the message scroller with data-sp-auto-scroll, plus bubbles and markers for the conversation itself.",
];
let chatIndex = 0;
let chatBusy = false;
let scripted = true;
const spacer = () => chatContent.lastElementChild;
const setBusy = (busy) => {
chatBusy = busy;
chatReset.disabled = busy;
chatSend.disabled = busy;
if (busy) chatContent.setAttribute("aria-busy", "true");
else chatContent.removeAttribute("aria-busy");
};
const streamReply = (paragraphs, done) => {
const el = assistantMessage();
const target = el.querySelector(".bubble-content");
chatContent.insertBefore(el, spacer());
let index = 0;
const next = () => {
if (index >= paragraphs.length) return done();
const words = paragraphs[index].split(" ");
const p = document.createElement("p");
target.append(p);
let at = 0;
const stream = setInterval(() => {
at += 1;
p.textContent = words.slice(0, at).join(" ");
if (at >= words.length) {
clearInterval(stream);
index += 1;
next();
}
}, 45);
};
next();
};
const reset = () => {
[...chatContent.children].slice(0, -1).forEach((el) => el.remove());
chatEmpty.classList.remove("hidden");
chatScroller.classList.add("hidden");
chatInput.value = "";
chatIndex = 0;
scripted = true;
};
reset();
chatReset.addEventListener("click", () => {
if (!chatBusy) reset();
});
chatInput.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
chatForm.requestSubmit();
}
});
chatForm.addEventListener("submit", (e) => {
e.preventDefault();
const text = chatInput.value.trim();
if (!text || chatBusy) return;
setBusy(true);
chatInput.value = "";
chatEmpty.classList.add("hidden");
chatScroller.classList.remove("hidden");
chatContent.insertBefore(userMessage(text), spacer());
const typing = document.createElement("div");
typing.className = "message-scroller-item";
typing.innerHTML =
'<div class="marker" role="status"><span class="marker-content shimmer">Thinking...</span></div>';
chatContent.insertBefore(typing, spacer());
setTimeout(() => {
typing.remove();
const greeting = /^(hi|hey|hello|yo|hola)\b/i.test(text);
let paragraphs;
if (greeting) {
paragraphs = [
"Hello! Ask about the scroll behavior, or just watch what happens to the thread while I answer.",
];
} else if (scripted) {
scripted = false;
paragraphs = firstReply;
} else {
paragraphs = [chatReplies[chatIndex++ % chatReplies.length]];
}
streamReply(paragraphs, () => {
setBusy(false);
chatInput.focus();
});
}, 900);
});
</script>
</div>Shopping Cart
A cart summary with product thumbnails, quantities, a subtotal, and a checkout action.
<div class="card">
<div class="card-header">
<div class="card-title">Shopping Cart</div>
<div class="card-description">You have 3 items in your cart.</div>
<div class="card-action -mr-2.5">
<button type="button" class="btn btn-ghost btn-sm">Clear</button>
</div>
</div>
<div class="card-content flex flex-col gap-6">
<div class="flex gap-4">
<div class="size-20 shrink-0 overflow-hidden rounded-md border">
<img
src="https://images.unsplash.com/photo-1578500494198-246f612d3b3d?rect=220,0,3264,3264&w=640&h=640&fit=crop&auto=format&q=100"
alt="Vintage Leather Sofa"
class="size-full object-cover"
/>
</div>
<div class="flex min-w-0 flex-1 flex-col">
<div class="flex items-start justify-between gap-3">
<h3 class="truncate text-sm font-medium">Vintage Leather Sofa</h3>
<button
type="button"
class="btn btn-ghost btn-icon -mt-1.5 -mr-1.5 size-6 text-muted-foreground"
aria-label="Remove Vintage Leather Sofa"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-x size-3.5"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
</button>
</div>
<p class="mt-1 truncate text-xs text-muted-foreground">
Full-grain aniline
</p>
<div class="mt-auto flex items-center justify-between">
<div class="btn-group rounded-md bg-muted">
<button
type="button"
class="btn btn-ghost btn-xs btn-icon"
aria-label="Decrease quantity of Vintage Leather Sofa"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-minus"
aria-hidden="true"
>
<path d="M5 12h14"></path>
</svg>
</button>
<div
class="btn-group-text border-0 bg-transparent px-2 text-xs shadow-none tabular-nums"
>
1
</div>
<button
type="button"
class="btn btn-ghost btn-xs btn-icon"
aria-label="Increase quantity of Vintage Leather Sofa"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-plus"
aria-hidden="true"
>
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg>
</button>
</div>
<p class="text-sm font-medium tabular-nums">
<span
class="mr-1.5 text-xs font-normal text-muted-foreground line-through"
>$1,099</span
>$899
</p>
</div>
</div>
</div>
<div class="flex gap-4">
<div class="size-20 shrink-0 overflow-hidden rounded-md border">
<img
src="https://images.unsplash.com/photo-1571139627661-cf707929f465?rect=0,57,2592,2592&w=640&h=640&fit=crop&auto=format&q=100"
alt="Cable Knit Sweater"
class="size-full object-cover"
/>
</div>
<div class="flex min-w-0 flex-1 flex-col">
<div class="flex items-start justify-between gap-3">
<h3 class="truncate text-sm font-medium">Cable Knit Sweater</h3>
<button
type="button"
class="btn btn-ghost btn-icon -mt-1.5 -mr-1.5 size-6 text-muted-foreground"
aria-label="Remove Cable Knit Sweater"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-x size-3.5"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
</button>
</div>
<p class="mt-1 truncate text-xs text-muted-foreground">
Cream · Size S
</p>
<div class="mt-auto flex items-center justify-between">
<div class="btn-group rounded-md bg-muted">
<button
type="button"
class="btn btn-ghost btn-xs btn-icon"
aria-label="Decrease quantity of Cable Knit Sweater"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-minus"
aria-hidden="true"
>
<path d="M5 12h14"></path>
</svg>
</button>
<div
class="btn-group-text border-0 bg-transparent px-2 text-xs shadow-none tabular-nums"
>
1
</div>
<button
type="button"
class="btn btn-ghost btn-xs btn-icon"
aria-label="Increase quantity of Cable Knit Sweater"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-plus"
aria-hidden="true"
>
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg>
</button>
</div>
<p class="text-sm font-medium tabular-nums">$79</p>
</div>
</div>
</div>
<div class="flex gap-4">
<div class="size-20 shrink-0 overflow-hidden rounded-md border">
<img
src="https://images.unsplash.com/photo-1710954962775-c46bd6a5f67f?rect=0,0,3072,3072&w=640&h=640&fit=crop&auto=format&q=100"
alt="Oversized Cotton Tee"
class="size-full object-cover"
/>
</div>
<div class="flex min-w-0 flex-1 flex-col">
<div class="flex items-start justify-between gap-3">
<h3 class="truncate text-sm font-medium">Oversized Cotton Tee</h3>
<button
type="button"
class="btn btn-ghost btn-icon -mt-1.5 -mr-1.5 size-6 text-muted-foreground"
aria-label="Remove Oversized Cotton Tee"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-x size-3.5"
aria-hidden="true"
>
<path d="M18 6 6 18"></path>
<path d="m6 6 12 12"></path>
</svg>
</button>
</div>
<p class="mt-1 truncate text-xs text-muted-foreground">
Sand · Size M · $29 each
</p>
<div class="mt-auto flex items-center justify-between">
<div class="btn-group rounded-md bg-muted">
<button
type="button"
class="btn btn-ghost btn-xs btn-icon"
aria-label="Decrease quantity of Oversized Cotton Tee"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-minus"
aria-hidden="true"
>
<path d="M5 12h14"></path>
</svg>
</button>
<div
class="btn-group-text border-0 bg-transparent px-2 text-xs shadow-none tabular-nums"
>
2
</div>
<button
type="button"
class="btn btn-ghost btn-xs btn-icon"
aria-label="Increase quantity of Oversized Cotton Tee"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-plus"
aria-hidden="true"
>
<path d="M5 12h14"></path>
<path d="M12 5v14"></path>
</svg>
</button>
</div>
<p class="text-sm font-medium tabular-nums">$58</p>
</div>
</div>
</div>
</div>
<div class="card-footer flex-col">
<div class="separator mb-4"></div>
<div class="flex w-full items-center justify-between">
<span class="text-sm text-muted-foreground">Subtotal</span
><span class="text-base font-semibold tabular-nums">$1,036</span>
</div>
<button class="btn mt-4 w-full">Checkout</button>
<p class="mt-3 w-full text-center text-xs text-muted-foreground">
Free shipping & returns on all orders
</p>
</div>
</div>Invoice Paid
A payment confirmation with a success icon and stacked actions.
<div class="card">
<div
class="card-content flex flex-col items-center gap-4 text-center text-balance"
>
<div
class="flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground"
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-check size-6"
aria-hidden="true"
>
<path d="M20 6 9 17l-5-5"></path>
</svg>
</div>
<div class="flex max-w-sm flex-col items-center gap-1">
<div class="text-lg font-medium tracking-tight">Invoice paid</div>
<div class="text-sm/relaxed text-muted-foreground">
You paid $17,975.30. A receipt copy was sent to [email protected].
</div>
</div>
<div class="flex w-full flex-col gap-3">
<button type="button" class="btn w-full">Next invoice</button
><button type="button" class="btn btn-outline w-full">Done</button>
</div>
</div>
</div>Attendance
Nested radio and checkbox options where selecting Private disables the sub-options with CSS alone.
<div class="card">
<div class="card-header">
<div class="card-title">Attendance</div>
<div class="card-description">Choose who can attend your event.</div>
</div>
<div class="card-content">
<div
class="group/att field-group gap-4"
role="radiogroup"
aria-label="Attendance"
>
<div class="field field-horizontal">
<input
type="radio"
class="radio"
id="lg-att-public"
name="lg-attendance"
checked=""
/>
<div class="field-content">
<label class="label" for="lg-att-public">Public</label>
<p class="field-description">
Tickets will be available to the general public.
</p>
<div
class="field-group mt-4 gap-4 transition-opacity group-has-[#lg-att-private:checked]/att:pointer-events-none group-has-[#lg-att-private:checked]/att:opacity-50"
>
<div class="field field-horizontal">
<input
type="checkbox"
class="checkbox"
id="lg-att-inperson"
checked=""
/>
<div class="field-content">
<label class="label" for="lg-att-inperson">In-person</label>
<p class="field-description">
Attendees will be at the event in person.
</p>
</div>
</div>
<div class="field field-horizontal">
<input type="checkbox" class="checkbox" id="lg-att-online" />
<div class="field-content">
<label class="label" for="lg-att-online">Online</label>
<p class="field-description">
Attendees will only be able to view the event online.
</p>
</div>
</div>
<div class="field field-horizontal">
<input type="checkbox" class="checkbox" id="lg-att-recorded" />
<div class="field-content">
<label class="label" for="lg-att-recorded">Recorded</label>
<p class="field-description">
A recording will be available after the event.
</p>
</div>
</div>
</div>
</div>
</div>
<div class="field field-horizontal">
<input
type="radio"
class="radio"
id="lg-att-private"
name="lg-attendance"
/>
<div class="field-content">
<label class="label" for="lg-att-private">Private</label>
<p class="field-description">
Tickets are not available to the general public.
</p>
</div>
</div>
</div>
</div>
</div>