Skip to content

VolpeIT/svelte-compound

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@volpe/svelte-compound

npm

A Vite plugin that enables the compound components pattern in Svelte projects.

What are Compound Components?

Compound components allow you to create components with semantically related sub-components that work together. Instead of passing many props, you compose components together.

Installation

npm install @volpe/svelte-compound
# or
pnpm add @volpe/svelte-compound
# or
bun add @volpe/svelte-compound

Usage

1. Configure Vite

Add the plugin to your vite.config.js:

import { defineConfig } from 'vite';
import { svelte } from '@sveltejs/vite-plugin-svelte';
import { compoundComponents } from '@volpe/svelte-compound';

export default defineConfig({
  plugins: [
    svelte(),
    compoundComponents()
  ]
});

2. Create Compound Components

Create a directory structure like this:

src/components/Card/
├── index.svelte      → Main Card component
├── _header.svelte    → Card._header subcomponent
└── _body.svelte      → Card._body subcomponent

Naming rules:

  • Subcomponents MUST start with _ (underscore)
  • Name after _ must be camelCase (e.g., _header.svelte, _body.svelte)
  • Components must be inside a components/ directory

Example index.svelte:

<script lang="ts">
  import type { Snippet } from "svelte"

  const { children }: { children?: Snippet } = $props()
</script>

<div class="card">
  {#if children}
    {@render children()}
  {/if}
</div>

<style>
  .card {
    border: 1px solid #ccc;
    padding: 1rem;
    border-radius: 4px;
  }
</style>

Example _header.svelte:

<script lang="ts">
  import type { Snippet } from "svelte"

  const { children }: { children?: Snippet } = $props()
</script>

<div class="card-header">
  {#if children}
    {@render children()}
  {/if}
</div>

<style>
  .card-header {
    font-weight: bold;
    border-bottom: 1px solid #eee;
    padding-bottom: 0.5rem;
  }
</style>

3. Use Compound Components

<script>
  import Card from '$lib/components/Card';
</script>

<Card>
  <Card._header>My Card Title</Card._header>
  <Card._body>Card content goes here</Card._body>
</Card>

Configuration Options

Option Type Default Description
exclude string[] ['routes'] Directories to exclude from scanning

Example:

compoundComponents({
  exclude: ['routes', 'admin']
})

How It Works

The plugin:

  1. Scans for components/ directories within your rootPath
  2. Detects folders containing index.svelte and _*.svelte subcomponents
  3. Generates an index.ts that exports the main component with subcomponents attached
  4. Uses Object.assign() to attach subcomponents to the main component

Generated index.ts example:

// Auto-generated by vite-plugin-svelte-compound-components
// Do not edit this file manually

import _header from './_header.svelte';
import _body from './_body.svelte';
import root from './index.svelte';

export default Object.assign(root, {
  _header,
  _body
});

TypeScript Support

TypeScript types work automatically. When you use Card._header, TypeScript will infer the correct component type.

Examples

Tabs Component

src/components/Tabs/
├── index.svelte      → <Tabs>
├── _tab.svelte       → <Tabs._tab>
└── _panel.svelte     → <Tabs._panel>

Usage:

<Tabs>
  <Tabs._tab>Tab 1</Tabs._tab>
  <Tabs._tab>Tab 2</Tabs._tab>

  <Tabs._panel>Content 1</Tabs._panel>
  <Tabs._panel>Content 2</Tabs._panel>
</Tabs>

Menu Component

src/components/Menu/
├── index.svelte
├── _item.svelte
├── _divider.svelte
└── _group.svelte

Usage:

<Menu>
  <Menu._item>New File</Menu._item>
  <Menu._item>Open</Menu._item>
  <Menu._divider />
  <Menu._group title="Recent">
    <Menu._item>file1.txt</Menu._item>
    <Menu._item>file2.txt</Menu._item>
  </Menu._group>
</Menu>

Features

  • Hot Module Replacement (HMR) support
  • TypeScript support
  • Works with SvelteKit and standalone Svelte + Vite
  • Zero runtime overhead
  • Auto-generates index.svelte and index.ts for new component folders
  • Recursive scanning of all components/ directories

Limitations

  • Only one level of nesting (e.g., Card._header works, but not Card._header._title)
  • Subcomponents must be in the same directory as the parent index.svelte
  • Subcomponent names must follow _camelCase pattern

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors