Live playground + per-component API reference at sveltastic-ui-docs.
Svelte 5 (runes) + Tailwind v4 component library. 26 components, one barrel import, every visual token overridable with one CSS line.
npm install sveltastic-ui svelte@^5 tailwindcss@^4 @tailwindcss/vite@^4 phosphor-svelte@^3// vite.config.ts
import tailwindcss from '@tailwindcss/vite';
import { sveltekit } from '@sveltejs/kit/vite';
export default {
plugins: [tailwindcss(), sveltekit()]
};<!-- src/routes/+layout.svelte -->
<script>
import 'sveltastic-ui/styles';
</script>Drop this inline script into <head> in src/app.html so the dark theme applies before the first paint — no white flash on dark-mode devices:
<!-- src/app.html, inside <head>, BEFORE %sveltekit.head% -->
<script>
(function () {
try {
var saved = localStorage.getItem('sveltastic-ui:theme');
var resolved =
saved === 'light' || saved === 'dark'
? saved
: window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
document.documentElement.setAttribute('data-theme', resolved);
} catch (_) {}
})();
</script>Then call theme.hydrate() once in your root layout onMount so the kit's reactive state reflects the attribute the script already set:
<script>
import { onMount } from 'svelte';
import { theme } from 'sveltastic-ui';
onMount(() => theme.hydrate());
</script><script lang="ts">
import { Button, notify, NotificationsHost } from 'sveltastic-ui';
</script>
<NotificationsHost />
<Button
color="primary"
onclick={() => notify({ title: 'Saved', color: 'success' })}
>
Save
</Button>- Button (+
ButtonGroup) - Input
- InputNumber
- Textarea
- Checkbox
- Radio
- Switch
- Select
- Slider
- Segmented
- Upload
- DateTimePicker
- Calendar
- Card
- Divider
- List (+
ListItem,ListGroup,ListDivider) - Collapse (+
CollapseGroup) - Tabs (+
Tab,TabList,TabPanel)
- Alert
- Avatar (+
AvatarGroup) - Chip
- Progress
- Tooltip
- Dialog
- Menu
- Pagination
notify(...)+<NotificationsHost />— toast notifications<ScrollbarHost />— kit-wide auto-hiding scrollbar
use:ripple— material-style click ripple
Every visual constant is a CSS variable in @theme. Rebrand with one rule:
@import 'sveltastic-ui/styles';
:root {
--primary: 21 94 117; /* R G B triplets — enables rgb(var(--primary) / 0.4) */
--radius: 10px;
--background: 250 250 250;
}
[data-theme='dark'] {
--background: 18 18 22;
}Dark mode: set data-theme="dark" on <html>. The kit picks it up automatically.
- Same prop name = same meaning everywhere.
color,size,variant,shape,disabled,loadingmean the same thing across every component. - One composition shape per component — named snippet props (
Card { header }), compound subcomponents (Tabs.Tab), or imperative (notify(...)). Never mixed. - Pure Svelte 5. No
createEventDispatcher, nosvelte/store, no<svelte:component>. Runes + callback props + actions. - SSR-safe. Zero top-level DOM access. Works in SvelteKit / Astro / vanilla Vite + Vinxi.
- Tree-shakable. Named re-exports only —
import { Button }ships only Button. - Resource discipline. Every action returns
destroy, every observer disconnects, every timer is cancellable. No leaks at 50 mount/unmount cycles. - i18n agnostic. Components accept text via snippet props; the kit imposes no locale.
- Accessible by default. Native semantics first; focus traps + keyboard navigation built in for overlays.
| Package | Range |
|---|---|
svelte |
^5 |
tailwindcss |
^4 |
phosphor-svelte |
^3 |
MIT © vdgmstd