stitch-svelte-components
Stitch → Svelte 5 / SvelteKit Components
You are a Svelte 5 engineer. You convert Stitch design screens into idiomatic Svelte components — using the runes API ($state, $props, $derived, $effect), not the legacy Options API. Components use scoped CSS with custom properties for theming, built-in Svelte transitions for animation, and accessible markup by default.
Note: This is the only Stitch skill that targets Svelte. The official
react-componentsskill targets Vite/React. Use this skill when the project uses SvelteKit.
When to use this skill
Use this skill when:
- The target project uses SvelteKit or Svelte 5 standalone
- You see
.sveltefiles,svelte.config.js, or+page.svelteconventions - The user mentions
svelte,sveltekit,$state,$props, orrunes
Prerequisites
- Access to the Stitch MCP server
- A Stitch project with at least one generated screen
- Target project uses Svelte 5 (runes enabled) — check
package.jsonfor"svelte": "^5"
Step 1: Retrieve the Stitch design
- Namespace discovery — Run
list_toolsto find the Stitch MCP prefix. Use it for all subsequent calls. - Fetch screen metadata — Call
[prefix]:get_screento retrieve design JSON. - Download HTML — Use the reliable downloader:
bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/source.html" - Visual reference — Check
screenshot.downloadUrlbefore writing code.
Step 2: SvelteKit file conventions
SvelteKit uses file-based routing. Map Stitch screens to this structure:
src/
├── routes/
│ ├── +layout.svelte ← Persistent shell (nav, footer)
│ ├── +layout.ts ← Layout load function (optional)
│ ├── +page.svelte ← Route page component
│ ├── [route]/
│ │ ├── +page.svelte ← Sub-route page
│ │ └── +page.ts ← Page load function (server-side data)
├── lib/
│ ├── components/ ← Reusable components
│ │ └── [Name].svelte
│ ├── data/
│ │ └── mockData.ts ← Decoupled static content
│ └── types/
│ └── index.ts ← Shared types
static/ ← Static assets
Key rules:
- Pages live in
src/routes/as+page.svelte - Reusable components live in
src/lib/components/ - Import
$lib/is an alias forsrc/lib/— always use it
Step 3: Svelte 5 runes API
Use runes exclusively. Never use the old export let, let x = 0 reactive syntax, or $: labels.
Props
<script lang="ts">
interface Props {
title: string
description?: string
onAction?: () => void
}
// $props() replaces export let
const { title, description = 'Default text', onAction }: Props = $props()
</script>
Reactive state
<script lang="ts">
// $state() replaces let count = 0
let count = $state(0)
let isOpen = $state(false)
// $derived() replaces $: doubled = count * 2
const doubled = $derived(count * 2)
// $effect() replaces onMount / afterUpdate for side effects
$effect(() => {
console.log('count changed:', count)
})
</script>
Event handling
<!-- Direct event attributes, no createEventDispatcher -->
<button onclick={() => count++}>Increment</button>
<button onclick={onAction}>Custom action</button>
Step 4: Scoped CSS with design tokens
Svelte scopes CSS to the component by default — use this aggressively. Map Stitch colors to custom properties in the :root (via +layout.svelte or app.css) and reference them in each component.
In src/app.css (global):
:root {
--color-background: #ffffff;
--color-surface: #f4f4f5;
--color-primary: /* dominant color from Stitch design */;
--color-primary-foreground: #ffffff;
--color-text: #09090b;
--color-text-muted: #71717a;
--color-border: #e4e4e7;
}
[data-theme='dark'] {
--color-background: #09090b;
--color-surface: #18181b;
--color-primary: /* same hue, adjusted for dark bg */;
--color-primary-foreground: #09090b;
--color-text: #fafafa;
--color-text-muted: #a1a1aa;
--color-border: #27272a;
}
In each component (scoped):
<style>
.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
border-radius: 0.5rem;
padding: 1.5rem;
}
.card:hover {
/* Scoped — won't leak to parent or children */
border-color: var(--color-primary);
}
</style>
Dark mode toggle — Add a $state in +layout.svelte:
<script lang="ts">
let theme = $state<'light' | 'dark'>('light')
function toggleTheme() {
theme = theme === 'light' ? 'dark' : 'light'
document.documentElement.setAttribute('data-theme', theme)
}
</script>
<svelte:element this="div" data-theme={theme}>
{@render children()}
</svelte:element>
Step 5: Built-in transitions and animations
Svelte has first-class transition support. Apply these from the Stitch design intent:
<script lang="ts">
import { fade, fly, slide, scale } from 'svelte/transition'
import { cubicOut } from 'svelte/easing'
let show = $state(false)
</script>
<!-- Page entry fade -->
<div transition:fade={{ duration: 200 }}>
Content that fades in
</div>
<!-- Slide panel -->
{#if isOpen}
<aside transition:fly={{ x: -300, duration: 300, easing: cubicOut }}>
Sidebar content
</aside>
{/if}
<!-- Collapsible section -->
{#if expanded}
<div transition:slide={{ duration: 200 }}>
Expandable content
</div>
{/if}
Always respect reduced motion:
<script lang="ts">
// Check user preference once
const prefersReducedMotion = $state(
typeof window !== 'undefined'
? window.matchMedia('(prefers-reduced-motion: reduce)').matches
: false
)
// Conditionally disable transitions
const transitionOptions = $derived(
prefersReducedMotion ? {} : { duration: 200 }
)
</script>
<div transition:fade={transitionOptions}>...</div>
Step 6: Accessibility in Svelte
Svelte's compiler warns about missing accessibility attributes — treat all compiler warnings as errors.
roleand ARIA: Addrolewhen using non-semantic elements. Always pair witharia-labeloraria-labelledby.bind:this: Use for programmatic focus management (e.g., focus trap in modals).- Keyboard handlers: Any
onclickhandler on a non-interactive element needsonkeydown/onkeyuptoo, or use a<button>. - Screen reader text: Use
class="sr-only"(define in app.css) for visually hidden labels.
<!-- Good: button with accessible label -->
<button
onclick={closeModal}
aria-label="Close dialog"
class="icon-btn"
>
<CloseIcon />
</button>
<!-- Good: Svelte dialog with focus trap -->
<dialog
bind:this={dialogEl}
aria-labelledby="dialog-title"
aria-modal="true"
>
<h2 id="dialog-title">{title}</h2>
</dialog>
Step 7: Execution steps
- Environment check — If
node_modulesmissing, runnpm install. - Data layer — Create
src/lib/data/mockData.tsfrom design content. - Component drafting — Use
resources/component-template.svelteas base. Replace all instances ofStitchComponentwith the actual component name. - CSS tokens — Add color tokens to
src/app.css. If usingstitch-design-system, import its generateddesign-tokens.cssinstead. - Wiring — Update
src/routes/+page.svelteto import and use the new components. Import from$lib/components/. - Quality check — Run through
resources/architecture-checklist.md. - Dev verification — Run
npm run dev. Toggle dark mode. Test keyboard navigation.
Troubleshooting
| Issue | Fix |
|---|---|
| Runes syntax error | Confirm svelte: ^5 in package.json. Old syntax is invalid in Svelte 5. |
$props() type error |
Add lang="ts" to <script> tag |
| CSS not scoped | Ensure styles are inside <style> block, not in a .css import |
| Transition not playing | Check prefers-reduced-motion isn't causing empty config |
$lib not resolving |
Confirm "paths": {"$lib/*": ["src/lib/*"]} in tsconfig.json |
| Dark mode flicker on load | Read theme from localStorage in a synchronous <svelte:head> script |
Integration with other skills
- stitch-design-system — Run first to generate
design-tokens.cssfor the CSS variable foundation. - stitch-animate — Run after for Svelte-specific transition patterns beyond the basics above.
- stitch-a11y — Run after for a full accessibility audit when the design has complex UI patterns.
References
resources/component-template.svelte— Production-ready Svelte 5 component boilerplateresources/architecture-checklist.md— Pre-ship quality checklistscripts/fetch-stitch.sh— Reliable GCS HTML downloader
More from gabelul/stitch-kit
stitch-mcp-get-screen
Retrieves full details of a specific Stitch screen — HTML download URL, screenshot URL, dimensions. This is the final step in design retrieval before code conversion.
35stitch-setup
Step-by-step installer for the stitch-kit plugin and Stitch MCP server. Use this when setting up the plugin for the first time, diagnosing connection issues, or helping a new user get Stitch running in Claude Code or Codex CLI.
33stitch-react-components
Converts Stitch designs into modular Vite + React components — TypeScript, theme-mapped Tailwind, dark mode via CSS variables, and clean component architecture. Use this for Vite/React apps without App Router. For Next.js 15 App Router, use stitch-nextjs-components instead.
24stitch-ui-prompt-architect
Builds Stitch-ready prompts via two paths — Path A enhances vague ideas into polished prompts, Path B merges a Design Spec JSON + user request into a structured [Context] [Layout] [Components] prompt.
23stitch-ideate
Conversational design ideation agent that researches trends, explores visual directions, and refines ideas through adaptive questioning — then produces a rich PRD document and auto-generates Stitch screens. Your design buddy that thinks deeply before designing.
23stitch-react-native-components
Converts Stitch mobile designs into React Native / Expo components — TypeScript, StyleSheet, Expo Router, dark mode via useColorScheme, and proper touch targets. Cross-platform iOS and Android.
22