We just published @abeedoo/radish-components — a Svelte 5 component library built on DaisyUI v5 and Tailwind CSS v4. 70+ components, zero custom CSS, all utility classes.
Playground · npm · GitHub
Why
We build a lot of admin panels and internal tools with SvelteKit. Every project needs the same things — data tables, forms, modals, toasts, dropdowns. DaisyUI gives us beautiful utility classes, but we were copying component files between projects and slowly watching them diverge.
So we extracted them into a shared library. Every component uses DaisyUI classes directly — no custom CSS, no CSS-in-JS, no shadow DOM. If you know DaisyUI, you already know how these are styled.
What's In It
70+ components across 7 categories:
- Actions — Button, Dropdown, Swap, ThemeController
- Data Display — Accordion, Avatar, Badge, Carousel, ChatBubble, CodeBlock, Collapse, Countdown, Kbd, List, Stat, Status, Table, Timeline
- Data Input — Calendar, Checkbox, FileInput, FormField, Radio, Range, Rating, Select, TextInput, Textarea, DateRangeInput, DropZone, SearchInput, Toggle
- Feedback — Alert, Loading, Progress, RadialProgress, Skeleton, Toast, Tooltip
- Layout — Card, Divider, Drawer, Footer, Hero, Stack
- Navigation — Breadcrumbs, Link, Menu, Navbar, Dock, Pagination, Steps
- Composites — AutoForm, ConfirmDialog, DataTable, EmptyState, Icon, Modal, PageHeader, ChatPanel, Tabs, JsonLd
Quick Start
npm install @abeedoo/radish-components
Tell Tailwind to scan the library's components:
@source "../node_modules/@abeedoo/radish-components/dist/**/*.svelte";
Use them:
<script>
import { Button, Modal, DataTable, toast } from '@abeedoo/radish-components';
</script>
<Button variant="primary" onclick={save}>Save</Button>
Svelte 5 Native
This isn't a Svelte 4 library with a compatibility shim. Every component uses runes:
$props()for reactive prop destructuring$state()and$derived()for internal reactivity$bindable()for two-way binding (toggles, inputs, modals)- Svelte 5 snippets for composition — no slot props, no render callbacks
<Modal bind:open title="Confirm">
<p>Are you sure?</p>
{#snippet footer()}
<Button variant="ghost" onclick={() => open = false}>Cancel</Button>
<Button variant="primary" onclick={confirm}>Yes</Button>
{/snippet}
</Modal>
Class composition uses $derived() so styles recalculate only when props change:
const classes = $derived(cn(
'btn',
variant && variantMap[variant],
size && sizeMap[size],
className
));
DataTable
The component I reach for most. Sorting, pagination, search, row selection, and row actions — all from props:
<DataTable
items={users}
columns={[
{ key: 'name', label: 'Name', sortable: true },
{ key: 'email', label: 'Email' },
{ key: 'role', label: 'Role', sortable: true }
]}
actions={[
{ label: 'Edit', onClick: editUser },
{ label: 'Delete', onClick: deleteUser, variant: 'error' }
]}
searchable
selectable
page={data.page}
totalPages={data.totalPages}
onPageChange={(p) => goto('?page=' + p)}
/>
No framework dependency — it uses callbacks instead of goto(), so it works in any Svelte app, not just SvelteKit.
Toast
Mount once in your layout, call from anywhere:
<!-- +layout.svelte -->
<script>
import { Toast } from '@abeedoo/radish-components';
</script>
<Toast />
// anywhere
import { toast } from '@abeedoo/radish-components/toast';
toast.success('Saved');
toast.error('Something went wrong');
Auto-dismisses. Supports custom durations. Store-based — no context providers, no prop drilling.
Icons
70+ inline SVG icons built into the Icon component. No icon font, no external fetches:
<Icon name="terminal" size={20} />
<Icon name="git-branch" />
<Icon name="clipboard" class="text-primary" />
The Design Philosophy
Every component spreads {...rest} to the underlying HTML element. Any DOM attribute, event handler, or aria-* prop just works:
<Button onclick={handler} aria-label="Save" data-testid="save-btn" />
No wrapper divs eating your events. No className vs class confusion. No special event syntax. Just Svelte.
The styling is pure DaisyUI utilities composed with a tiny cn() helper. If you want to override anything, pass a class prop — it gets merged, not replaced. If you want a different theme, set data-theme on any parent element. It's DaisyUI all the way down.
npm install @abeedoo/radish-components
Peer deps: svelte ^5, tailwindcss ^4, daisyui ^5
Check out the playground to see everything live.