Component decomposition and architecture guidelines for SvelteKit/Svelte 5 apps. Use when creating new components, deciding how to split code, reviewing component structure, refactoring nested components, or when unsure whether to extract a component. Triggers on phrases like "where should this go", "too many components", "too nested", "extract component", "component structure", "file organization", "props drilling", "refactor components", "review architecture", or questions about component boundaries.
Guidelines for decomposing SvelteKit applications into maintainable component hierarchies.
+page.svelte → Orchestrator (data wiring, layout, minimal UI)
└─ Feature → Self-contained capability (owns its logic + state)
└─ UI → Pure presentation (props in, events out)
Target: Maximum 3 levels of custom components. Not a hard rule, but exceeding 4-5 levels signals structural problems.
| Type | Responsibility | Owns State? | Location |
|------|----------------|-------------|----------|
| Page | Data orchestration, layout composition | Receives from load | routes/**/+page.svelte |
| Feature | Encapsulates complete capability | Yes, local state | lib/components/features/ |
| UI | Pure presentation, fully controlled | No | lib/components/ui/ |
Feature components are the main abstraction boundary. They should be understandable in isolation.
Extract when ANY of these apply:
Avoid creating components that:
A <div class="grid grid-cols-2"> in the parent is clearer than a <TwoColumnLayout> wrapper.
Is this reused elsewhere?
└─ Yes → Extract
└─ No → Is it complex (>250 lines or multiple concerns)?
└─ Yes → Extract as Feature
└─ No → Does it have independent state?
└─ Yes → Consider extracting
└─ No → Keep inline
src/lib/components/
├── ui/ # Design system primitives
│ ├── Button.svelte
│ ├── Input.svelte
│ ├── Card.svelte
│ └── Badge.svelte
├── features/ # Self-contained feature blocks
│ ├── auth/
│ │ ├── LoginForm.svelte
│ │ └── UserMenu.svelte
│ └── dashboard/
│ ├── StatsCard.svelte
│ └── ActivityFeed.svelte
└── layout/ # App-wide layout components (optional)
├── Navbar.svelte
└── Footer.svelte
ProposalBuilder.svelteDroneSpecsTable not DataTable*Form, *Card, *List, *Modalfeatures/billing/, features/onboarding/<!-- Feature: owns its logic -->
<script>
let { projectId } = $props();
let data = $state(null);
// fetches and manages its own state
</script>
<!-- UI: pure presentation -->
<script>
let { label, variant = 'primary', onclick } = $props();
</script>
| Pattern | Problem | Fix |
|---------|---------|-----|
| Wrapper-only components | Adds indirection without value | Inline the markup |
| Prop tunneling | Passing same prop through 4+ levels | Use context or flatten |
| God components | 500+ lines, multiple responsibilities | Split by concern |
| Premature extraction | Single-use 30-line component | Keep inline until reused |
| Layout-as-component | <TwoColumn> for one-time use | Use CSS classes directly |
| Nested state sync | Child and parent both manage same state | Single source of truth |
When reviewing existing component structure:
See references/audit.md for detailed checklist.
Flattening deep nesting:
Splitting god components:
Fixing prop drilling:
Search for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer