Variants

Components in this registry define their variants with tailwind-variants, declared inline in the <script module> block of the .svelte file — see button.svelte for the reference example. There’s no separate *.variants.ts file; keeping tv() next to the markup it styles keeps the two in sync.

Pattern

1<script lang="ts" module>
2  import { type VariantProps, tv } from "tailwind-variants";
3  import { cn, type WithElementRef } from "$lib/utils.js";
4
5  export const buttonVariants = tv({
6    base: "inline-flex items-center rounded-md font-medium disabled:opacity-50",
7    variants: {
8      variant: {
9        default: "bg-primary text-primary-foreground hover:bg-primary/80",
10        outline: "border-border bg-background hover:bg-muted",
11      },
12      size: {
13        default: "h-9 px-4 text-sm",
14        sm: "h-8 px-3 text-xs",
15      },
16    },
17    defaultVariants: {
18      variant: "default",
19      size: "default",
20    },
21  });
22
23  export type ButtonVariant = VariantProps<typeof buttonVariants>["variant"];
24  export type ButtonSize = VariantProps<typeof buttonVariants>["size"];
25</script>
26
27<script lang="ts">
28  let { class: className, variant = "default", size = "default", ...restProps } = $props();
29</script>
30
31<button class={cn(buttonVariants({ variant, size }), className)} {...restProps} />
  • Export the tv() result (buttonVariants) so consumers and stories can call it directly.
  • Derive prop types from VariantProps<typeof buttonVariants>, not a hand-written string union.
  • Compose the final class list with cn() from $lib/utils.js so caller-supplied class can still override the recipe.

Checklist

  • Use only tv from tailwind-variants — not class-variance-authority / cva.
  • Keep the recipe in the same file as the component; don’t split it into a sibling .variants.ts unless a future item genuinely needs to share one recipe across multiple components.
  • Export VariantProps type aliases next to the recipe.
  • List every source file the item needs (component + any shared recipe) in _registry.svx’s files.