A delightful CLI for Svelte 5 component registry
Ship beautiful, accessible components with ease š¹
ā ļø This project is unstable and intended for personal use only.
Installation ⢠Quick Start ⢠Commands ⢠Resolution ⢠Creating Components ⢠Hosting ⢠Packages ⢠Contributing
Rumm is a comprehensive component registry system for Svelte 5, inspired by shadcn/ui. Unlike traditional component libraries, Rumm doesn't install packages ā it copies source code into your project, giving you full ownership and the freedom to customize everything.
$lib/components/ without nested prefixes.d.ts files@tailwindcss/viteRumm consists of three main packages:
| Package | Description | Status |
|---|---|---|
@svelte-registry/cli |
Command-line interface for component management | Stable |
@svelte-registry/www |
Web application serving the component registry | Stable |
svelte-registry |
Root monorepo with shared configuration | Meta-package |
Install the CLI globally:
# Using pnpm (recommended)
pnpm add -g rumm
# Using npm
npm install -g rumm
# Using yarn
yarn global add rumm
# Using bun
bun add -g rumm
Clone and set up the monorepo:
git clone https://github.com/TheRaj71/Rum.git
cd Rum
pnpm install
pnpm build
Navigate to your SvelteKit project and run:
rumm init
This will:
components.json configuration filecn() utility function to src/lib/utils.tsAdd components by name from the official registry:
rumm add button
rumm add card
rumm add button card counter # Add multiple at once
Or add from any URL:
rumm add https://example.com/r/datepicker.json
<script>
import { Button } from '$lib/components/button';
import { Card, CardHeader, CardTitle, CardContent } from '$lib/components/card';
</script>
<Card>
<CardHeader>
<CardTitle>Welcome</CardTitle>
</CardHeader>
<CardContent>
<Button>Get Started</Button>
</CardContent>
</Card>
That's it! The components are now part of your project.
Rumm implements a sophisticated component resolution system inspired by shadcn/ui:
Direct URL ā Fetch immediately
rumm add https://example.com/r/button.json
Namespaced Reference ā Use specific registry
rumm add @acme/button # ā acme registry only
Name-based Search ā Lookup in registry.json
rumm add button # ā search items array in registry.json
Fallback Pattern ā Try /r/{name}.json
rumm add button # ā fetch /r/button.json
When you run rumm add button, Rumm:
registry.json from your configured registryitems array using .find(item => item.name === 'button')Components install to clean, predictable paths:
src/lib/
āāā components/
ā āāā button/ # UI components
ā ā āāā Button.svelte
ā ā āāā index.ts
ā āāā card/ # Multi-file components
ā āāā Card.svelte
ā āāā CardHeader.svelte
ā āāā index.ts
āāā hooks/
āāā counter/ # Reactive hooks
āāā counter.svelte.ts
āāā index.ts
No nested prefixes like default/ui/button/ - just clean, logical paths!
rumm initInitialize your SvelteKit project for Rumm.
rumm init [options]
Options:
-c, --cwd <path> Working directory (default: current directory)
-s, --style <style> Style/theme to use (default: "default")
-f, --force Force overwrite existing files
-v, --verbose Show verbose output
--registry <url> Custom registry URL (default: https://rumcli.pages.dev/r/registry.json)
What it does:
components.json with sensible defaultscn() helper for class mergingrumm addAdd components to your project.
rumm add <components...> [options]
Arguments:
components Component names, URLs, or namespaced references
Options:
-c, --cwd <path> Working directory
-o, --overwrite Overwrite existing files without prompting
-r, --registry <name> Use a specific registry from your config
-v, --verbose Show verbose output
--skip-install Skip npm dependency installation
--yes Skip confirmation prompts
Examples:
# Add by name (smart resolution)
rumm add button
# Add multiple components
rumm add button card dialog tooltip
# Add from URL
rumm add https://acme.dev/r/auth-form.json
# Add with namespaced reference
rumm add @acme/button
# Add from specific registry
rumm add button -r acme
# Force overwrite
rumm add button --overwrite
# Skip dependency installation
rumm add button --skip-install
Auto-initialization: If you haven't run rumm init, the add command will automatically initialize your project when you add your first component.
rumm buildBuild your component registry from source files.
rumm build [options]
Options:
-c, --cwd <path> Working directory
-s, --source <dir> Source directory (default: "src/lib/registry")
-o, --output <dir> Output directory (default: "static/r")
-n, --name <name> Registry name
--homepage <url> Registry homepage URL
-v, --verbose Show verbose output
--dry-run Validate without writing files
What it does:
registry.json index with component metadataBuild Process:
Examples:
# Basic build
rumm build
# Custom source/output
rumm build -s src/components -o dist/registry
# Dry run for validation
rumm build --dry-run --verbose
# Build with custom name
rumm build -n "my-components" --homepage "https://my-site.com"
rumm serveStart a local server to test your registry.
rumm serve [options]
Options:
-c, --cwd <path> Working directory
-d, --dir <dir> Directory with registry files (default: "static/r")
-p, --port <port> Port to listen on (default: 5555)
-v, --verbose Show verbose output
Features:
Examples:
# Serve on default port
rumm serve
# Serve on custom port
rumm serve -p 3000
# Serve from custom directory
rumm serve -d dist/registry
# Test in another terminal
curl http://localhost:5555/registry.json
Rumm uses a components.json file in your project root:
{
"$schema": "https://rum.dev/schema/config.json",
"style": "default",
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app.css",
"baseColor": "slate"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils",
"hooks": "$lib/hooks",
"lib": "$lib"
},
"registries": {
"default": "https://rumcli.pages.dev/r/registry.json"
}
}
style (string)Default style/theme to use. Currently only "default" is supported.
tailwind (object)Tailwind CSS configuration:
config: Path to Tailwind config filecss: Path to CSS file where variables are injectedbaseColor: Base color scheme (slate, gray, zinc, etc.)aliases (object)SvelteKit path aliases:
components: Where UI components are installedutils: Where utility functions are placedhooks: Where reactive hooks are installedlib: General lib directoryregistries (record)Registry URL mappings. Each registry can be:
"default": "https://example.com/r/registry.json""private": {"url": "...", "headers": {"Authorization": "Bearer token"}}"template": "https://example.com/r/{name}.json"Configure multiple registries for different sources:
{
"registries": {
"default": "https://rumcli.pages.dev/r/registry.json",
"acme": "https://acme.dev/r/registry.json",
"internal": {
"url": "https://internal.company.com/r/registry.json",
"headers": {
"Authorization": "Bearer ${REGISTRY_TOKEN}"
}
},
"template": "https://cdn.example.com/{name}.json"
}
}
Usage:
rumm add button # Uses default registry
rumm add button -r acme # Uses acme registry
rumm add @acme/button # Namespaced reference
Want to create your own component registry? Here's how:
my-registry/
āāā src/lib/registry/
ā āāā default/ # Style/theme directory
ā ā āāā ui/ # UI components (buttons, cards, etc.)
ā ā ā āāā button/
ā ā ā ā āāā Button.svelte
ā ā ā ā āāā index.ts
ā ā ā āāā card/
ā ā ā āāā Card.svelte
ā ā ā āāā CardHeader.svelte
ā ā ā āāā CardContent.svelte
ā ā ā āāā index.ts
ā ā āāā hooks/ # Reactive hooks
ā ā āāā counter/
ā ā āāā counter.svelte.ts
ā ā āāā index.ts
ā āāā .gitkeep
āāā static/r/ # Generated registry JSON files
ā āāā registry.json # Registry index
ā āāā button.json # Individual component
ā āāā card.json
āāā package.json
āāā components.json # Rumm configuration
āāā svelte.config.js
Rumm supports different component types:
Located in src/lib/registry/default/ui/, these are single or multi-file Svelte components:
ui/button/
āāā Button.svelte # Main component
āāā index.ts # Exports
Located in src/lib/registry/default/ui/, these are complex multi-file components:
ui/card/
āāā Card.svelte
āāā CardHeader.svelte
āāā CardContent.svelte
āāā CardFooter.svelte
āāā CardTitle.svelte
āāā CardDescription.svelte
āāā index.ts
Located in src/lib/registry/default/hooks/, these are reactive utilities:
hooks/counter/
āāā counter.svelte.ts # Reactive hook
āāā index.ts # Exports
<!-- src/lib/registry/default/ui/button/Button.svelte -->
<script lang="ts">
import { tv, type VariantProps } from 'tailwind-variants';
import type { Snippet } from 'svelte';
import type { HTMLButtonAttributes } from 'svelte/elements';
const buttonVariants = tv({
base: 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
variants: {
variant: {
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-9 px-4 py-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
});
type ButtonVariants = VariantProps<typeof buttonVariants>;
interface Props extends HTMLButtonAttributes {
variant?: ButtonVariants['variant'];
size?: ButtonVariants['size'];
children?: Snippet;
class?: string;
}
let {
variant = 'default',
size = 'default',
children,
class: className,
...restProps
}: Props = $props();
</script>
<button class={buttonVariants({ variant, size, class: className })} {...restProps}>
{@render children?.()}
</button>
// src/lib/registry/default/hooks/counter/counter.svelte.ts
interface CounterOptions {
initial?: number;
min?: number;
max?: number;
step?: number;
}
interface Counter {
readonly count: number;
increment: () => void;
decrement: () => void;
reset: () => void;
set: (value: number) => void;
}
export function createCounter(options: CounterOptions = {}): Counter {
const { initial = 0, min = -Infinity, max = Infinity, step = 1 } = options;
let count = $state(initial);
function clamp(value: number): number {
return Math.min(Math.max(value, min), max);
}
return {
get count() {
return count;
},
increment: () => {
count = clamp(count + step);
},
decrement: () => {
count = clamp(count - step);
},
reset: () => {
count = initial;
},
set: (value: number) => {
count = clamp(value);
},
};
}
# Build the registry
rumm build
# Start local server for testing
rumm serve
# Test in another project
rumm add http://localhost:5555/button.json
Add JSDoc comments to include metadata:
<!--
@name button
@description A versatile button component with multiple variants
@author Rumm Team
@categories ui, forms
-->
Dependencies are auto-detected from imports, or you can specify them manually:
<!--
@dependencies tailwind-variants, clsx
@registryDependencies icon
-->
Deploy your SvelteKit app to Vercel. The static/r/ folder is served automatically:
Your registry will be available at https://your-app.vercel.app/r/registry.json
Similar to Vercel, with excellent global CDN performance.
For static hosting:
rum buildstatic/r/ to a gh-pages branchPoint your domain to any of the above services:
https://rum.dev/r/button.jsonhttps://components.yourcompany.com/r/button.json| Package | Purpose | Version |
|---|---|---|
svelte |
UI framework | ^5.0.0 |
zod |
Schema validation | ^3.25.67 |
commander |
CLI framework | ^13.1.0 |
tailwind-variants |
Component variants | ^3.2.2 |
clsx + tailwind-merge |
Class utilities | ^2.1.1 + ^3.3.1 |
Rumm automatically detects and works with all major package managers:
| Package Manager | Lock File | Install Command | Global Install |
|---|---|---|---|
| npm | package-lock.json |
npm install |
npm install -g rumm |
| pnpm | pnpm-lock.yaml |
pnpm add |
pnpm add -g rumm |
| yarn | yarn.lock |
yarn add |
yarn global add rumm |
| bun | bun.lockb |
bun add |
bun add -g rumm |
This project uses pnpm workspaces:
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Start development servers
pnpm dev
# CLI development
pnpm --filter rumm run dev
# Web app development
pnpm --filter @svelte-registry/www run dev
# Development server
pnpm dev
# Build for production
pnpm build
# Preview production build
pnpm preview
# Build component registry
pnpm registry:build
# Serve registry locally (for testing)
pnpm dev:server
# Type checking
pnpm check
# Linting
pnpm lint
# Formatting
pnpm format
# Run all tests
pnpm test
# Run CLI tests
pnpm --filter rumm run test
# Run with coverage
pnpm test --coverage
@svelte-registry/cliThe command-line interface for Rumm. Install globally or use with npx.
Features:
Installation:
pnpm add -g rumm
@svelte-registry/wwwWeb application that serves the component registry.
Features:
Development:
pnpm --filter @svelte-registry/www run dev
We welcome contributions! Please see our Contributing Guide for details.
git checkout -b feature/your-featurepnpm testMIT Ā© TheRaj71
rumm works with any package manager. Install it globally or use it directly with npx/pnpm dlx:
# Using pnpm (recommended)
pnpm add -g rumm
# Using npm
npm install -g rumm
# Using bun
bun add -g rumm
# Or use without installing
pnpm dlx rumm add button
Navigate to your SvelteKit project and run:
rumm init
This will:
components.json configuration filecn() utility function to src/lib/utils.tsAdd components by name from the official registry:
rumm add button
rumm add card
rumm add button card dialog # Add multiple at once
Or add from any URL:
rumm add https://example.com/r/datepicker.json
<script>
import { Button } from '$lib/components/button';
import { Card, CardHeader, CardTitle, CardContent } from '$lib/components/card';
</script>
<Card>
<CardHeader>
<CardTitle>Welcome</CardTitle>
</CardHeader>
<CardContent>
<Button>Get Started</Button>
</CardContent>
</Card>
That's it! The components are now part of your project.
rumm initInitialize your SvelteKit project for rumm.
rumm init [options]
Options:
-c, --cwd <path> Working directory (default: current directory)
-s, --style <style> Style/theme to use (default: "default")
-f, --force Force overwrite existing files
-v, --verbose Show verbose output
What it does:
components.json with sensible defaultscn() helper for class mergingrumm addAdd components to your project.
rumm add <components...> [options]
Arguments:
components Component names or URLs to add
Options:
-c, --cwd <path> Working directory
-o, --overwrite Overwrite existing files without prompting
-r, --registry <name> Use a specific registry from your config
-v, --verbose Show verbose output
--skip-install Skip npm dependency installation
Examples:
# Add a single component
rumm add button
# Add multiple components
rumm add button card dialog tooltip
# Add from a URL
rumm add https://acme.dev/r/auth-form.json
# Add with auto-overwrite
rumm add button --overwrite
Auto-initialization: If you haven't run rumm init, the add command will automatically initialize your project when you add your first component.
rumm buildBuild your component registry from source files.
rumm build [options]
Options:
-c, --cwd <path> Working directory
-s, --source <dir> Source directory (default: "src/lib/registry")
-o, --output <dir> Output directory (default: "static/r")
-n, --name <name> Registry name
--homepage <url> Registry homepage URL
-v, --verbose Show verbose output
--dry-run Validate without writing files
What it does:
registry.json indexrumm serveStart a local server to test your registry.
rumm serve [options]
Options:
-c, --cwd <path> Working directory
-d, --dir <dir> Directory with registry files (default: "static/r")
-p, --port <port> Port to listen on (default: 5555)
-v, --verbose Show verbose output
Perfect for testing your registry locally before deploying:
# In your registry project
rumm build
rumm serve
# In another project
rumm add http://localhost:5555/button.json
rumm uses a components.json file in your project root:
{
"$schema": "https://rum.dev/schema/config.json",
"style": "default",
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/app.css",
"baseColor": "slate"
},
"aliases": {
"components": "$lib/components",
"utils": "$lib/utils",
"hooks": "$lib/hooks",
"lib": "$lib"
},
"registries": {
"default": "https://rum.dev/r/registry.json"
}
}
You can configure multiple registries:
{
"registries": {
"default": "https://rum.dev/r/registry.json",
"acme": "https://acme.dev/r/registry.json",
"internal": {
"url": "https://internal.company.com/r/registry.json",
"headers": {
"Authorization": "Bearer ${REGISTRY_TOKEN}"
}
}
}
}
Then specify which registry to use:
rumm add button -r acme
Want to create your own component registry? Here's how:
my-registry/
āāā src/lib/registry/
ā āāā ui/
ā ā āāā button/
ā ā ā āāā Button.svelte
ā ā ā āāā index.ts
ā ā āāā card/
ā ā āāā Card.svelte
ā ā āāā CardHeader.svelte
ā ā āāā CardContent.svelte
ā ā āāā index.ts
ā āāā hooks/
ā āāā counter/
ā āāā counter.svelte.ts
ā āāā index.ts
āāā static/r/ # Generated registry files
āāā package.json
<!-- src/lib/registry/ui/button/Button.svelte -->
<script lang="ts">
import type { Snippet } from 'svelte';
import { tv, type VariantProps } from 'tailwind-variants';
const button = tv({
base: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
outline: 'border border-input bg-background hover:bg-accent',
ghost: 'hover:bg-accent hover:text-accent-foreground',
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 px-3',
lg: 'h-11 px-8',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
});
type ButtonVariants = VariantProps<typeof button>;
interface Props {
variant?: ButtonVariants['variant'];
size?: ButtonVariants['size'];
class?: string;
children: Snippet;
onclick?: () => void;
}
let { variant, size, class: className, children, onclick }: Props = $props();
</script>
<button class={button({ variant, size, class: className })} {onclick}>
{@render children()}
</button>
# Build the registry
rumm build
# Start local server for testing
rumm serve
# Test in another project
rumm add http://localhost:5555/button.json
Add JSDoc comments to include metadata:
<!--
@name button
@description A versatile button component with multiple variants
@author Your Name
@categories ui, forms
-->
Dependencies are auto-detected from imports, or you can specify them manually:
<!--
@dependencies tailwind-variants, clsx
@registryDependencies icon
-->
Deploy your SvelteKit app to Vercel. The static/r/ folder is served automatically:
Your registry will be available at https://your-app.vercel.app/r/registry.json
For static hosting:
rum buildstatic/r/ to a gh-pages branchSimilar to Vercel, with excellent global CDN performance.
Point your domain to any of the above services:
https://rum.dev/r/button.jsonhttps://components.yourcompany.com/r/button.jsonrumm works with all major package managers:
| Package Manager | Lock File | Install Command |
|---|---|---|
| npm | package-lock.json |
npm install |
| pnpm | pnpm-lock.yaml |
pnpm add |
| yarn | yarn.lock |
yarn add |
| bun | bun.lockb |
bun add |
rumm automatically detects your package manager and uses the correct install command.
rumm supports both Tailwind CSS v3 and v4:
Tailwind v3 - Detected via tailwind.config.ts or tailwind.config.js
Tailwind v4 - Detected via CSS imports:
@import 'tailwindcss';
All components are built with Svelte 5 best practices:
$state, $derived, $effect for reactive state{@render}$props() for component properties.svelte.ts files - Shared reactive logic (hooks)