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.