adc-ui-kit

Vue 3 UI components for Tailwind CSS v4 — one CSS import, overridable design tokens
Install
npm install adc-ui-kit
Latest Version:1.0.0
Vue:3
License:MIT
Last Updated:Oct 12, 2026
Links: npm
Maintainer: pureuser

adc-ui-kit

English · ภาษาไทย

Vue 3 UI components styled with Tailwind CSS v4: 33 components and 2 composables. Setup is one CSS import, and you can override the design tokens.

Docs and live examples: https://ui-kit.purepure2553.workers.dev

Requirements

  • Vue 3.5+
  • Tailwind CSS v4 with @tailwindcss/vite
  • vue-router is optional. Without it, everything works except the to prop of UiButton.

Installation

npm i adc-ui-kit
npm i -D tailwindcss @tailwindcss/vite   # if you don't have them yet
// vite.config.ts
import tailwindcss from '@tailwindcss/vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'

export default defineConfig({
    plugins: [vue(), tailwindcss()],
})

Setup

1. CSS — one line. Use it in place of @import 'tailwindcss'. Don't include both.

/* src/style.css */
@import 'adc-ui-kit/tailwind.css';

This file already includes Tailwind, the design tokens, base styles, and the @source rule that lets Tailwind find the kit's classes.

2. Font. The kit uses Noto Sans Thai but doesn't ship the font file. Load the font yourself, or override --font-sans (see Theming).

<!-- index.html -->
<link
    href="https://fonts.googleapis.com/css2?family=Noto+Sans+Thai:wght@400;500;600;700&display=swap"
    rel="stylesheet"
/>

3. App.vue. Add the toast and loader outlets once.

<script setup lang="ts">
import { UiLoaderOverlay, UiToast } from 'adc-ui-kit'
</script>

<template>
    <RouterView />
    <UiToast />
    <UiLoaderOverlay />
</template>

Usage

<script setup lang="ts">
import { UiButton, UiInput, UiModal, UiSelect, useToast, type SelectOption } from 'adc-ui-kit'
import { Plus } from 'lucide-vue-next'
import { ref } from 'vue'

const name = ref('')
const branch = ref<string | null>(null)
const open = ref(false)
const toast = useToast()

const BRANCHES: SelectOption[] = [
    { value: 'hq', label: 'Head office' },
    { value: 'east', label: 'East branch' },
]

function save() {
    open.value = false
    toast.success('Saved')
}
</script>

<template>
    <UiButton :icon="Plus" @click="open = true">New customer</UiButton>

    <UiModal v-model="open" title="New customer">
        <div class="flex flex-col gap-4">
            <UiInput v-model="name" label="Name" required />
            <UiSelect v-model="branch" label="Branch" :options="BRANCHES" searchable />
        </div>
        <template #footer>
            <UiButton variant="ghost" @click="open = false">Cancel</UiButton>
            <UiButton @click="save">Save</UiButton>
        </template>
    </UiModal>
</template>

Icons come from lucide-vue-next, which is installed along with the kit. Pass the icon component itself, e.g. :icon="Plus".

Theming

Add an @theme block after the import and list only the tokens you want to change. Kit components (including the date picker calendar) and your own classes follow the new values.

@import 'adc-ui-kit/tailwind.css';

@theme {
    --color-primary: #7c3aed;
    --color-primary-hover: #6d28d9;
    --color-primary-soft: #ede9fe;
    --radius-control: 12px;
}
Group Tokens Example classes
Brand --color-primary · -hover · -soft bg-primary text-primary bg-primary-soft
Surface & line --color-ground · --color-panel · --color-line · --color-line-strong bg-ground bg-panel border-line
Text --color-ink · --color-muted · --color-faint text-ink text-muted text-faint
Status --color-ok · --color-warn · --color-danger (+ -soft) text-ok bg-warn-soft text-danger
Radius --radius-control · --radius-card · --radius-auth rounded-control rounded-card
Font size --text-tiny · --text-small · --text-body · --text-lead (+ --line-height) text-small text-body
Font --font-sans · --font-mono font-sans font-mono
Z-index --z-index-dropdown · overlay · modal · toast · tooltip z-modal z-toast
Layout --spacing-sidebar w-sidebar

Every token is also a CSS variable, so you can use var(--color-primary) in your own CSS.

Components

v-model is the value you bind to the component. Every form control also accepts label, required, hint, error and disabled.

Component Purpose v-model Main props Events / slots
UiButton Button – variant (primary · outline · ghost · danger) · size (sm · md · lg) · icon · iconAlign · block · loading · type · to @click · default slot
UiButtonIcon Icon-only button – icon · label (required, read by screen readers) · variant · size · loading @click
UiCard Content box – title · description · icon · padding (none · sm · md · lg) · surface (panel · draft) #actions · default
UiAlert Message box – tone · title · closable · noIcon @close · default
UiBadge Small status label – tone · pill default
UiDivider Divider line – – default (text in the middle)
UiSpinner Loading spinner – size (px) –
UiSkeleton Loading placeholder – width · height · rounded (sm · full) –
UiEmpty Empty state – icon · title · description default (action)
UiStat KPI number card – label · value · trend · trendTone · loading –
UiTable Data table – columns (TableColumn[]) · rows · rowKey · loading · clickable · sortKey · sortDir · emptyTitle @row-click · @sort · #cell-<key> · #empty-action
UiTabs Tabs T items (TabItem[]) @change
UiPagination Pagination number (page) total · perPage · siblings @change
UiProgress Progress bar – value · max · tone · size · label –
UiField Label / hint / error wrapper for your own fields – label · required · hint · error default { id, invalid, describedBy }
UiInput Text input string type · placeholder · icon · clearable · loading · formats · uppercase · maxlength @enter · @clear · @change
UiTextarea Multi-line input string rows · maxlength (shows a counter) @change
UiInputCurrency Money input (adds commas) number | null decimals · prefix · max @change
UiSelect Dropdown T | null options (SelectOption[]) · searchable · clearable · placeholder @change
UiAutocomplete Pick from a list or type your own value string options · maxlength · noResultText @change
UiCheckbox Checkbox boolean label · description · indeterminate @change
UiRadio Radio group T | null options · inline @change
UiToggle Switch boolean label · description @change
UiFileUpload File upload with drag and drop File[] accept · multiple · maxSizeMb @change · @reject
UiImagePreview Image from a URL or a File – source · alt · ratio (square · video) · removable @remove
UiModal Dialog boolean (open) title · description · icon · size (sm … xl · full) · dismissible @close · default · #footer
UiConfirm Confirmation dialog boolean (open) title · message · confirmText · cancelText · tone · loading @confirm · @cancel
UiToast Toast outlet, placed once in App.vue – – driven by useToast()
UiTooltip Tooltip on hover or focus – content · placement (top · bottom · left · right) default (trigger)
UiLoaderOverlay Full-screen loader outlet, placed once in App.vue – – driven by useLoader()
UiDatePicker Date picker (Thai calendar) Date | null minDate · maxDate · clearable · placeholder @change
UiDateRangePicker Date range picker Date[] minDate · maxDate · clearable @change
UiTimePicker Time picker string | null ('HH:mm') step (minutes, default 30) · min · max · searchable @change

tone is one of primary, ok, warn, danger or neutral.

Table example

<script setup lang="ts">
import { UiBadge, UiTable, type TableColumn } from 'adc-ui-kit'

const COLUMNS: TableColumn[] = [
    { key: 'code', label: 'Code', mono: true, width: '120px' },
    { key: 'name', label: 'Name' },
    { key: 'status', label: 'Status', align: 'center' },
]
const rows = [{ code: 'C-001', name: 'Somchai', status: 'active' }]
</script>

<template>
    <UiTable :columns="COLUMNS" :rows="rows" :row-key="(row) => row.code">
        <template #cell-status="{ row }">
            <UiBadge tone="ok">{{ row.status }}</UiBadge>
        </template>
    </UiTable>
</template>

Set sortable: true on a column to get @sort events. The table doesn't reorder rows itself, so sort the data at its source (for example, your API).

Composables

import { useLoader, useToast } from 'adc-ui-kit'

const toast = useToast()
toast.success('Saved')
toast.error('Save failed', { title: 'Error', duration: 0 }) // duration 0 = stays until closed
toast.warning('...')
toast.info('...')

const { withLoader, isLoading } = useLoader()
await withLoader(() => api.save(payload)) // shows the full-screen loader until the task finishes

Both composables need their outlet (<UiToast /> or <UiLoaderOverlay />) in App.vue.

Types

import type { Align, ButtonVariant, SelectOption, Size, SortDirection, TabItem, TableColumn, Tone, Toast } from 'adc-ui-kit'

Notes

  • Light mode only.

ภาษาไทย

UI component สำหรับ Vue 3 ที่ใช้ Tailwind CSS v4 มี component 33 ตัวและ composable 2 ตัว ตั้งค่า CSS บรรทัดเดียว และเปลี่ยน design token ได้

เอกสารและตัวอย่างสด: https://ui-kit.purepure2553.workers.dev/?lang=th

สิ่งที่ต้องมี

  • Vue 3.5 ขึ้นไป
  • Tailwind CSS v4 และ @tailwindcss/vite
  • vue-router ไม่บังคับ ไม่มีก็ใช้ได้ทุกตัว ยกเว้น prop to ของ UiButton ที่จะไม่ทำงาน

ติดตั้ง

npm i adc-ui-kit
npm i -D tailwindcss @tailwindcss/vite   # ถ้ายังไม่มี
// vite.config.ts
import tailwindcss from '@tailwindcss/vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'

export default defineConfig({
    plugins: [vue(), tailwindcss()],
})

ตั้งค่า

1. CSS บรรทัดเดียว ใส่บรรทัดนี้แทน @import 'tailwindcss' ห้ามใส่ทั้งสองบรรทัด

/* src/style.css */
@import 'adc-ui-kit/tailwind.css';

ไฟล์นี้มีครบแล้ว: Tailwind ทั้งชุด, design token, base style และ @source ที่ทำให้ Tailwind หา class ของ kit เจอ

2. ฟอนต์ kit ใช้ Noto Sans Thai แต่ไม่ได้แนบไฟล์ฟอนต์มา ต้องโหลดเอง หรือทับ --font-sans เป็นฟอนต์อื่น (ดู เปลี่ยนธีม)

<!-- index.html -->
<link
    href="https://fonts.googleapis.com/css2?family=Noto+Sans+Thai:wght@400;500;600;700&display=swap"
    rel="stylesheet"
/>

3. App.vue วางจุดแสดง toast กับ loader ไว้ที่เดียวทั้งแอป

<script setup lang="ts">
import { UiLoaderOverlay, UiToast } from 'adc-ui-kit'
</script>

<template>
    <RouterView />
    <UiToast />
    <UiLoaderOverlay />
</template>

วิธีใช้

<script setup lang="ts">
import { UiButton, UiInput, UiModal, UiSelect, useToast, type SelectOption } from 'adc-ui-kit'
import { Plus } from 'lucide-vue-next'
import { ref } from 'vue'

const name = ref('')
const branch = ref<string | null>(null)
const open = ref(false)
const toast = useToast()

const BRANCHES: SelectOption[] = [
    { value: 'hq', label: 'สำนักงานใหญ่' },
    { value: 'east', label: 'สาขาตะวันออก' },
]

function save() {
    open.value = false
    toast.success('บันทึกแล้ว')
}
</script>

<template>
    <UiButton :icon="Plus" @click="open = true">เพิ่มลูกค้า</UiButton>

    <UiModal v-model="open" title="เพิ่มลูกค้า">
        <div class="flex flex-col gap-4">
            <UiInput v-model="name" label="ชื่อ" required />
            <UiSelect v-model="branch" label="สาขา" :options="BRANCHES" searchable />
        </div>
        <template #footer>
            <UiButton variant="ghost" @click="open = false">ยกเลิก</UiButton>
            <UiButton @click="save">บันทึก</UiButton>
        </template>
    </UiModal>
</template>

ไอคอนใช้ lucide-vue-next ซึ่งติดตั้งมาพร้อม kit แล้ว ส่งเป็นตัว component เลย เช่น :icon="Plus"

เปลี่ยนธีม

เขียน @theme ต่อจากบรรทัด import แล้วใส่เฉพาะ token ที่อยากเปลี่ยน ทั้ง component ของ kit (รวมปฏิทินด้วย) และ class ของโปรเจกต์เองจะเปลี่ยนตาม

@import 'adc-ui-kit/tailwind.css';

@theme {
    --color-primary: #7c3aed;
    --color-primary-hover: #6d28d9;
    --color-primary-soft: #ede9fe;
    --radius-control: 12px;
}
กลุ่ม token ตัวอย่าง class
สีแบรนด์ --color-primary · -hover · -soft bg-primary text-primary bg-primary-soft
พื้นหลังและเส้น --color-ground · --color-panel · --color-line · --color-line-strong bg-ground bg-panel border-line
ตัวอักษร --color-ink · --color-muted · --color-faint text-ink text-muted text-faint
สถานะ --color-ok · --color-warn · --color-danger (+ -soft) text-ok bg-warn-soft text-danger
มุมโค้ง --radius-control · --radius-card · --radius-auth rounded-control rounded-card
ขนาดตัวอักษร --text-tiny · --text-small · --text-body · --text-lead (+ --line-height) text-small text-body
ฟอนต์ --font-sans · --font-mono font-sans font-mono
ลำดับซ้อนทับ --z-index-dropdown · overlay · modal · toast · tooltip z-modal z-toast
โครงหน้า --spacing-sidebar w-sidebar

token ทุกตัวเป็น CSS variable ด้วย ใน CSS ของโปรเจกต์เขียน var(--color-primary) ได้เลย

Component

v-model คือค่าที่ผูกกับตัวแปร ส่วนช่องฟอร์มทุกตัวรับ label, required, hint, error และ disabled ได้ด้วย

Component ใช้ทำอะไร v-model prop หลัก event / slot
UiButton ปุ่ม – variant (primary · outline · ghost · danger) · size (sm · md · lg) · icon · iconAlign · block · loading · type · to @click · default slot
UiButtonIcon ปุ่มไอคอนล้วน – icon · label (บังคับใส่ ให้โปรแกรมอ่านหน้าจออ่าน) · variant · size · loading @click
UiCard กล่องเนื้อหา – title · description · icon · padding (none · sm · md · lg) · surface (panel · draft) #actions · default
UiAlert กล่องแจ้งเตือน – tone · title · closable · noIcon @close · default
UiBadge ป้ายสถานะเล็ก – tone · pill default
UiDivider เส้นคั่น – – default (ข้อความกลางเส้น)
UiSpinner วงกลมหมุนตอนโหลด – size (px) –
UiSkeleton โครงร่างเทาระหว่างรอข้อมูล – width · height · rounded (sm · full) –
UiEmpty สถานะไม่มีข้อมูล – icon · title · description default (ปุ่มชวนทำต่อ)
UiStat การ์ดตัวเลข KPI – label · value · trend · trendTone · loading –
UiTable ตาราง – columns (TableColumn[]) · rows · rowKey · loading · clickable · sortKey · sortDir · emptyTitle @row-click · @sort · #cell-<key> · #empty-action
UiTabs แท็บ T items (TabItem[]) @change
UiPagination แบ่งหน้า number (หน้าปัจจุบัน) total · perPage · siblings @change
UiProgress แถบความคืบหน้า – value · max · tone · size · label –
UiField ตัวห่อ label / hint / error ให้ช่องที่ทำเอง – label · required · hint · error default { id, invalid, describedBy }
UiInput ช่องกรอกข้อความ string type · placeholder · icon · clearable · loading · formats · uppercase · maxlength @enter · @clear · @change
UiTextarea ช่องกรอกหลายบรรทัด string rows · maxlength (มีตัวนับ) @change
UiInputCurrency ช่องจำนวนเงิน (ใส่ comma ให้เอง) number | null decimals · prefix · max @change
UiSelect dropdown T | null options (SelectOption[]) · searchable · clearable · placeholder @change
UiAutocomplete เลือกจากรายการ หรือพิมพ์เอง string options · maxlength · noResultText @change
UiCheckbox ช่องติ๊ก boolean label · description · indeterminate @change
UiRadio ตัวเลือกแบบเลือกได้อย่างเดียว T | null options · inline @change
UiToggle สวิตช์เปิด/ปิด boolean label · description @change
UiFileUpload อัปโหลดไฟล์ (ลากวางได้) File[] accept · multiple · maxSizeMb @change · @reject
UiImagePreview แสดงรูปจาก URL หรือ File – source · alt · ratio (square · video) · removable @remove
UiModal หน้าต่างซ้อน boolean (เปิดอยู่ไหม) title · description · icon · size (sm … xl · full) · dismissible @close · default · #footer
UiConfirm กล่องยืนยัน boolean (เปิดอยู่ไหม) title · message · confirmText · cancelText · tone · loading @confirm · @cancel
UiToast จุดแสดง toast (วางที่ App.vue ตัวเดียว) – – สั่งผ่าน useToast()
UiTooltip คำอธิบายลอยตอน hover / focus – content · placement (top · bottom · left · right) default (ตัวที่ชี้)
UiLoaderOverlay ม่านโหลดเต็มจอ (วางที่ App.vue ตัวเดียว) – – สั่งผ่าน useLoader()
UiDatePicker เลือกวันที่ (ปฏิทินไทย) Date | null minDate · maxDate · clearable · placeholder @change
UiDateRangePicker เลือกช่วงวันที่ Date[] minDate · maxDate · clearable @change
UiTimePicker เลือกเวลา string | null ('HH:mm') step (นาที ค่าเริ่มต้น 30) · min · max · searchable @change

tone เลือกได้จาก primary, ok, warn, danger และ neutral

ตัวอย่างตาราง

<script setup lang="ts">
import { UiBadge, UiTable, type TableColumn } from 'adc-ui-kit'

const COLUMNS: TableColumn[] = [
    { key: 'code', label: 'รหัส', mono: true, width: '120px' },
    { key: 'name', label: 'ชื่อ' },
    { key: 'status', label: 'สถานะ', align: 'center' },
]
const rows = [{ code: 'C-001', name: 'สมชาย', status: 'ใช้งาน' }]
</script>

<template>
    <UiTable :columns="COLUMNS" :rows="rows" :row-key="(row) => row.code">
        <template #cell-status="{ row }">
            <UiBadge tone="ok">{{ row.status }}</UiBadge>
        </template>
    </UiTable>
</template>

ใส่ sortable: true ในคอลัมน์แล้วตารางจะยิง @sort ให้ แต่ตารางไม่เรียงแถวเอง ต้องไปเรียงที่ต้นทางของข้อมูล เช่น API

Composable

import { useLoader, useToast } from 'adc-ui-kit'

const toast = useToast()
toast.success('บันทึกแล้ว')
toast.error('บันทึกไม่สำเร็จ', { title: 'ผิดพลาด', duration: 0 }) // duration 0 = ค้างจนกดปิด
toast.warning('...')
toast.info('...')

const { withLoader, isLoading } = useLoader()
await withLoader(() => api.save(payload)) // ม่านโหลดขึ้นจนกว่างานจะเสร็จ

ทั้งสองตัวต้องมีจุดแสดง (<UiToast /> หรือ <UiLoaderOverlay />) อยู่ใน App.vue

Type

import type { Align, ButtonVariant, SelectOption, Size, SortDirection, TabItem, TableColumn, Tone, Toast } from 'adc-ui-kit'

ข้อควรรู้

  • มีแต่โทนสว่าง ไม่มี dark mode

Related Packages

tailwind-config-viewer

View your Tailwind CSS config file...visually!

19,524,150 2,211
tailwindcss-themeable

multiple themes support for tailwindcss, with Dracula built-in

7,097 59
gurunkit

Vue UI Component Library Built with Tailwind CSS.

1,758
@peterdkc/vtw-color-table

A TailwindCSS color palette viewer using VueJS

486 1
@vezironi/veyra-ui

Vue 3 UI component kit built with Tailwind CSS v4, with dark and light themes.

556 0

Version History

Version Released Vue License
1.0.0 ^3.5.0 MIT
0.1.1 ^3.5.0 Proprietary
0.1.0 ^3.5.0 Proprietary
Pre-releases (1)
Version Released License
0.0.0-stage