Help us improve
Share bugs, ideas, or general feedback.
From svelte
This skill should be used when the user asks to "build a page", "add a component", "create a form", "add a dialog", "set up shadcn-svelte", "add dark mode", "style with tailwind", "create a dashboard", "add a data table", or works with any UI in Svelte 5. Also trigger when the user mentions shadcn-svelte, bits-ui, Tailwind CSS, formsnap, superforms, tailwind-variants, mode-watcher, or component architecture. Even if the user doesn't explicitly mention UI libraries, use this skill whenever building visual interfaces in SvelteKit — it prevents common mistakes like using Svelte 4 syntax, wrong Tailwind v4 patterns, and poor component architecture.
npx claudepluginhub maxnoller/claude-code-plugins --plugin svelteHow this skill is triggered — by the user, by Claude, or both
Slash command
/svelte:svelte-ui-stackThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Build production UIs in Svelte 5 using shadcn-svelte, bits-ui, and Tailwind CSS v4.
Enforces Svelte 5 best practices in SvelteKit: runes ($state, $derived, $effect), $props(), $bindable(), load functions, form actions, and SSR patterns to fix outdated Svelte 4 code.
Provides Svelte patterns for web components, libraries (Bits UI, Ark UI, Melt UI), form handling, and third-party UI integrations.
Converts Stitch designs into Svelte 5 / SvelteKit components using runes API, scoped CSS with custom properties, built-in transitions, TypeScript, dark mode, and accessible markup. Use for SvelteKit projects with .svelte files.
Share bugs, ideas, or general feedback.
Build production UIs in Svelte 5 using shadcn-svelte, bits-ui, and Tailwind CSS v4.
These are the things that have changed since training cutoff. Everything else (component design, software architecture, state management principles) — Claude already knows.
| Correct (Svelte 5) | Wrong (Svelte 4) |
|---|---|
let { x } = $props() | export let x |
let { ...rest } = $props() | $$restProps |
{@render children?.()} | <slot /> |
{@render header?.()} | <slot name="header" /> |
onclick={handler} | on:click={handler} |
| Callback props | createEventDispatcher |
$bindable() | Just export let for two-way |
ref = $bindable(null) | bind:this from parent |
// vite.config.ts — Vite plugin, not PostCSS
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
plugins: [tailwindcss(), sveltekit()],
});
All configuration in CSS. Colors in OKLCH. tw-animate-css replaces tailwindcss-animate. See references/tailwind-v4.md for the full theme setup.
| Current | Deprecated |
|---|---|
tailwind-variants (tv()) | class-variance-authority (cva) |
@lucide/svelte (deep imports: @lucide/svelte/icons/check) | lucide-svelte (barrel imports) |
tw-animate-css | tailwindcss-animate |
bits-ui Command | cmdk-sv |
@tanstack/table-core + createSvelteTable | svelte-headless-table |
zod4 / zod4Client (superforms adapters) | zod / zodClient |
pnpm dlx shadcn-svelte@latest init
pnpm dlx shadcn-svelte@latest add button dialog form input
pnpm dlx shadcn-svelte@latest add --all
All shadcn-svelte components follow this structure:
<script lang="ts" module>
import { tv } from "tailwind-variants";
export const myVariants = tv({ base: "...", variants: { ... } });
</script>
<script lang="ts">
import { cn } from "$lib/utils.js";
let {
class: className, variant, ref = $bindable(null),
children, ...restProps
}: Props = $props();
</script>
<div bind:this={ref} data-slot="my-component"
class={cn(myVariants({ variant }), className)} {...restProps}>
{@render children?.()}
</div>
The cn() utility merges classes (clsx + tailwind-merge). {...restProps} spread enables attachments and bits-ui features to pass through.
Compound component pattern with dot notation. The child snippet overrides rendered elements:
<Dialog.Trigger>
{#snippet child({ props })}
<Button {...props} variant="outline">Custom trigger</Button>
{/snippet}
</Dialog.Trigger>
For floating components (Popover, Tooltip, Select), the child snippet also receives wrapperProps — spread both.
See references/shadcn-components.md for Dialog, Sheet, Command, Select, Accordion, Toast, DataTable patterns.
Svelte's value proposition is simplicity. State, logic, and markup live together in .svelte files — that colocation is the feature. Don't add abstraction layers Svelte was designed to not need.
When a component grows large, extract visual sub-components with narrow props. This is the Svelte way — not extracting state into separate files.
<!-- Before: 800-line +page.svelte -->
<!-- After: thin page + focused sub-components -->
<PageToolbar {services} onDeploy={handleDeploy} onRestart={handleRestart} />
<ServiceGrid {filteredServices} {statusMap} />
{#if services.length === 0}
<EmptyState {slug} {env} />
{/if}
<ConfirmDialogs bind:deleteOpen bind:deployOpen {onConfirm} />
Each sub-component receives only what it needs — not a god object. The state stays in the page component that owns it.
.svelte.ts files enable runes outside components. Use them for reusable reactive logic shared across multiple components — not for extracting page-local state.
Good uses: createPagination(), createInfiniteScroll(), useAutoRefresh(), createFormState()
Not ideal: extracting a single page's state into a factory just to make the component shorter.
When passing reactive values to .svelte.ts functions, use getter functions for primitives (() => count) since reactivity persists through property access. Object $state proxies can be passed directly.
createContext (Svelte 5.40+) for SSR-safe, subtree-scoped state:
import { createContext } from 'svelte';
export const [getUser, setUser] = createContext<User>();
Never use module-level $state for user-specific data in SSR apps — it leaks between requests.
See references/component-architecture.md for the full decision guide on state patterns, file types, and project structure.
<form method="POST" use:enhance>
<Form.Field {form} name="email">
<Form.Control>
{#snippet children({ props })}
<Form.Label>Email</Form.Label>
<Input {...props} bind:value={$formData.email} />
{/snippet}
</Form.Control>
<Form.FieldErrors />
</Form.Field>
</form>
<ModeWatcher /> <!-- in +layout.svelte -->
Toggle: toggleMode(), setMode('light' | 'dark'), resetMode().
Use createSvelteTable with renderComponent/renderSnippet. See references/forms-and-tables.md.
references/component-architecture.md — State patterns, .svelte.ts usage, project structure, context APIreferences/tailwind-v4.md — Full CSS theme setup, OKLCH colors, dark mode, custom variantsreferences/shadcn-components.md — Component catalog with code: Dialog, Sheet, Command, Select, Accordion, Toast, DataTable, DropdownMenureferences/forms-and-tables.md — Formsnap + Superforms + TanStack Table complete setup