Svelte app ui
  • Svelte 79.7%
  • TypeScript 11.6%
  • CSS 4.1%
  • MDX 2.8%
  • JavaScript 1.1%
  • Other 0.7%
Find a file
Kens e3f8462f1a release v0.7.38 - permanent fix for Tailwind class detection
- form-utils.getColSpanClass now returns literal class strings via a
  lookup map instead of a template literal. Tailwind's scanner can
  detect every possible class (col-span-12 sm:col-span-1..12) at
  build time without any consumer-side safelist.
- base.css adds '@source "../**/*.{svelte,ts,js}"' so every consumer
  project automatically scans kuku-ui's own source files when building
  Tailwind CSS. Consumers no longer need to configure @source or
  safelist dynamic classes themselves.

Together these changes remove the entire class of "missing responsive
classes" bugs that consumers hit when kuku-ui generated classes via
template literals.
2026-04-24 19:50:55 +05:30
.storybook svg replaced to lucide 2026-04-08 16:31:29 +05:30
docs/superpowers component created VerifyOTP 2026-04-14 16:17:01 +05:30
src release v0.7.38 - permanent fix for Tailwind class detection 2026-04-24 19:50:55 +05:30
static tweaking on form 2026-03-26 12:15:19 +05:30
.editorconfig Form init fix 2025-11-30 21:00:15 +05:30
.gitignore DataTable and DataList 2026-02-28 16:25:08 +05:30
.npmrc initial setup 2025-11-10 11:36:53 +05:30
.postcss.config.js v0.4.6 - Fixed Prettier compatibility by downgrading to v3.3.3 2025-12-10 19:37:47 +05:30
.prettierignore v0.4.6 - Fixed Prettier compatibility by downgrading to v3.3.3 2025-12-10 19:37:47 +05:30
.prettierrc initial setup 2025-11-10 11:36:53 +05:30
CLAUDE.md v0.4.6 - Fixed Prettier compatibility by downgrading to v3.3.3 2025-12-10 19:37:47 +05:30
LICENSE Initial commit 2025-09-25 16:22:11 +00:00
llms.txt v0.7.7 - DataSelect UX improvements, docs update 2026-03-04 12:15:26 +05:30
Makefile relase tag change 2026-02-28 12:18:14 +05:30
package-lock.json release v0.7.38 - permanent fix for Tailwind class detection 2026-04-24 19:50:55 +05:30
package.json release v0.7.38 - permanent fix for Tailwind class detection 2026-04-24 19:50:55 +05:30
README.md use as: 2026-03-07 17:26:34 +05:30
svelte.config.js initial setup 2025-11-10 11:36:53 +05:30
tailwind.config.js trying to fix css bug 2025-12-12 15:29:05 +05:30
tsconfig.json v0.4.6 - Fixed Prettier compatibility by downgrading to v3.3.3 2025-12-10 19:37:47 +05:30
vite.config.ts trying to fix css bug 2025-12-12 15:29:05 +05:30

kuku-ui

Beautiful, accessible Svelte 5 + DaisyUI component library with Tailwind CSS 4.

MIT License

Installation

npm install kuku-ui

Peer Dependencies

Your project needs these installed:

npm install svelte@^5 @sveltejs/kit@^2 tailwindcss@^4 daisyui@^5 yup@^1
npm install @tailwindcss/vite @tailwindcss/forms @tailwindcss/typography

CSS Setup

Add these lines to your main CSS file (e.g. app.css), after @import "tailwindcss":

@import "tailwindcss";
@source "../node_modules/kuku-ui/src/lib/**/*.svelte";
@import "kuku-ui/base.css";
  • @source — tells Tailwind to scan kuku-ui component templates for utility classes
  • @import "kuku-ui/base.css" — provides shared theme tokens, base styles, and utility overrides that components depend on

If you use the Form component (which generates grid column classes dynamically), also add:

@source inline("sm:col-span-1 sm:col-span-2 sm:col-span-3 sm:col-span-4 sm:col-span-5 sm:col-span-6 sm:col-span-7 sm:col-span-8 sm:col-span-9 sm:col-span-10 sm:col-span-11 sm:col-span-12");

Quick Start

Import components from kuku-ui:

<script lang="ts">
  import { Button, Modal, toast, Toaster } from 'kuku-ui';
</script>

<Button look="primary" onclick={() => toast.success('Done', 'It works!')}>
  Click me
</Button>

<Toaster />

Components

Buttons

Component Description
Button Primary button with variants, loading state, and size options
ButtonIcon Button with icon + text side-by-side
ButtonLink Anchor element styled as a button
BtnFloat Fixed floating action button (bottom-right)
BtnSwap Toggle button with swap animation (sun/moon theme toggle)
<Button look="primary" size="md" busy={loading} outline>Save</Button>
<Button look="error" size="sm" circle><Cancel /></Button>
<ButtonLink href="/about" look="accent">About</ButtonLink>

Button looks: neutral | primary | secondary | accent | info | success | warning | error | ghost | link

Form System

The Form component renders fields from a schema with built-in Yup validation:

<script lang="ts">
  import { Form, strRequired, emailRequired, type FormSchema } from 'kuku-ui';

  const schema: FormSchema = [
    [
      [
        { name: 'name', type: 'text', label: 'Full Name', col: '6', validate: strRequired },
        { name: 'email', type: 'email', label: 'Email', col: '6', validate: emailRequired }
      ]
    ],
    [
      [
        { name: 'bio', type: 'textarea', label: 'Bio', col: '12' }
      ]
    ]
  ];

  async function handleSubmit(data: { name: string; email: string; bio: string }) {
    await api.save(data);
  }
</script>

<Form id="profile" {schema} onSubmit={handleSubmit} submitText="Save Profile" />

Individual Form Components

Component Description
Textbox Text/email/password/number input with autocomplete
Textarea Multi-line text input
Select Dropdown with options
Checkbox Checkbox with label
Radio Radio button group
SearchList Async search with single/multi-select and badges
Phone International phone input with country selector and masking
DateTimePicker Calendar picker with optional time selection
TimePicker Time-only picker with minute intervals
<Textbox name="city" label="City" value={city} onChange={(n, v) => city = v} />

<SearchList
  name="tags"
  label="Tags"
  multiple
  onSearch={async (q) => await fetchTags(q)}
  bind:value={selectedTags}
/>

<DateTimePicker
  name="date"
  label="Event Date"
  format="YYYY-MM-DD"
  showTime
  minuteInterval={15}
  bind:value={eventDate}
/>

<Phone name="phone" label="Phone" defaultCountry="US" bind:value={phone} />

Validation Helpers

import {
  strRequired, strOptional,
  emailRequired, emailOptional,
  numRequired,
  validatePwd, validatePhone,
  validateMinLength, validateMaxLength,
  validateNumberRange, validateUrl
} from 'kuku-ui';

Modals

<script lang="ts">
  import { Modal, ModalWithForm } from 'kuku-ui';
  let open = $state(false);
</script>

<!-- Simple modal -->
<Modal bind:open title="Confirm" onOk={handleOk} onCancel={() => open = false}>
  <p>Are you sure?</p>
</Modal>

<!-- Modal with integrated form -->
<ModalWithForm
  {open}
  title="Edit User"
  formID="edit-user"
  formSchema={schema}
  formInitialData={user}
  onSubmit={handleSubmit}
  onCancel={() => open = false}
/>

Sizes: xs | sm | md | lg | xl

Toast Notifications

<script lang="ts">
  import { toast, Toaster } from 'kuku-ui';
</script>

<!-- Place once in your layout -->
<Toaster />

<!-- Trigger from anywhere -->
<button onclick={() => toast.success('Saved', 'Your changes have been saved')}>
  Save
</button>
<button onclick={() => toast.error('Error', 'Something went wrong')}>
  Error
</button>

Methods: toast.info() | toast.success() | toast.warning() | toast.error()

Each accepts (title, message, clearInSeconds?) where clearInSeconds defaults to 7 (use 0 for persistent).

Alert

<Alert type="warning" title="Heads up">
  This action cannot be undone.
</Alert>

Types: info | success | warning | error

ConfirmAction

Wraps any trigger (button, link, toggle) with a confirmation dialog:

<ConfirmAction
  title="Delete Item"
  onConfirm={async () => await deleteItem(id)}
  askForReason
  btnLook="error"
>
  Delete
</ConfirmAction>

Icons

39 SVG icons with optional outline variants:

<script lang="ts">
  import { Calendar, CalendarOutline, Home, Trash, Search } from 'kuku-ui';
  import Icon from 'kuku-ui/svg/Icon.svelte';
</script>

<!-- Direct import -->
<Calendar cls="h-5 w-5" />

<!-- Icon wrapper with outline toggle -->
<Icon icon="home" outline />

Available icons: bar3 calendar cancel checkcircle chevron-left chevron-right error eye folder home info moon pencil pencil-square success sun search trash user warning

DataTable

Server-side paginated table with virtual scrolling, sorting, search, row selection, and mobile card view:

<script lang="ts">
  import { DataTable, type DataTableColumn, type DataTableFetchParams } from 'kuku-ui';

  type User = { id: number; name: string; email: string; role: string };

  const columns: DataTableColumn<User>[] = [
    { key: 'name', label: 'Name', sortable: true },
    { key: 'email', label: 'Email', sortable: true },
    { key: 'role', label: 'Role' }
  ];

  async function fetchUsers({ page, pageSize, search, sortKey, sortDir }: DataTableFetchParams) {
    const res = await fetch(`/api/users?page=${page}&size=${pageSize}&q=${search ?? ''}`);
    return res.json(); // { rows: User[], total: number }
  }
</script>

<DataTable {columns} onFetch={fetchUsers} pageSize={50} cls="h-[600px]" />

Features: virtual scroll for 100K+ rows, column sorting, search with debounce, row selection (selectable), custom cell renderers, mobile-responsive card view, toolbar snippet, empty state snippet.

DataList

Simpler alternative to DataTable — renders arbitrary items via a snippet instead of columns. Same virtual scroll + infinite scroll engine:

<script lang="ts">
  import { DataList, type DataTableFetchParams } from 'kuku-ui';

  type User = { id: number; name: string; email: string };

  async function fetchUsers({ page, pageSize, search }: DataTableFetchParams) {
    const res = await fetch(`/api/users?page=${page}&size=${pageSize}&q=${search ?? ''}`);
    return res.json(); // { rows: User[], total: number }
  }
</script>

<DataList fetcher={fetchUsers} pageSize={50} itemHeight={80} cls="h-[600px]">
  {#snippet itemSnippet(row: User)}
    <div class="flex items-center gap-4 border-b px-4 py-3">
      <div class="font-medium">{row.name}</div>
      <div class="text-sm text-gray-500">{row.email}</div>
    </div>
  {/snippet}
</DataList>

Features: virtual scroll for 100K+ rows, infinite scroll pagination, search with debounce, toolbar snippet, empty state snippet, refresh() method.

DataSelect

Versatile select/combobox with search, single/multi-select, grouped options, async search, and creatable items:

<script lang="ts">
  import { DataSelect, type Option, type OptionGroup } from 'kuku-ui';

  const colors: Option[] = [
    { key: 'red', value: 'Red' },
    { key: 'blue', value: 'Blue' }
  ];

  let selected = $state<Option | undefined>();
  let multiSelected = $state<Option[]>([]);
</script>

<!-- Single select with static options -->
<DataSelect name="color" label="Color" options={colors} bind:value={selected} />

<!-- Multi-select with async search and creatable -->
<DataSelect
  name="tags"
  label="Tags"
  multiple
  creatable
  onSearch={async (q) => await fetchTags(q)}
  bind:value={multiSelected}
/>

Features: client-side filtering, async search with debounce, grouped options (OptionGroup[]), multi-select with badge chips, creatable items, custom item/group/create snippets, clearable, keyboard navigation.

Other Components

Component Description
Badge Small decorative label with color and size variants

Portal Action

Teleport DOM elements to a different location:

<script lang="ts">
  import { portal, createPortal } from 'kuku-ui';
</script>

<!-- Target location -->
<div use:createPortal={'my-portal'}></div>

<!-- Content will be moved to target -->
<div use:portal={'my-portal'}>
  This renders at the target location
</div>

Drag and Drop

Custom drag-and-drop with HTML5 Drag API and Pointer Events:

<script lang="ts">
  import { draggable } from 'kuku-ui/drag-and-drop/action-dragable';
  import { droppable } from 'kuku-ui/drag-and-drop/action-dropable';
</script>

<div use:draggable={{ container: 'list-a', dragData: item }}>
  Drag me
</div>

<div use:droppable={{
  container: 'list-b',
  callbacks: {
    onDrop: (data) => handleDrop(data)
  }
}}>
  Drop here
</div>

Styling

kuku-ui uses Tailwind CSS 4 with DaisyUI 5. Components accept cls props for custom classes:

<Button cls="w-full mt-4" look="primary">Full Width</Button>

All form components support a col prop ('1'-'12') for grid layout control and a size prop ('xs' | 'sm' | 'md' | 'lg').

Development

npm run dev          # Dev server
npm run storybook    # Storybook on :6006
npm run check        # Type check
npm run build        # Build library
npm run format       # Prettier

License

MIT