# W4C UI — referensi lengkap > Design system Waste4Change: token warna, komponen Vue untuk Nuxt 4, dan situs > dokumentasi. Didistribusikan sebagai Nuxt layer (`@waste4change/ui`): tanpa > langkah build, komponen terdaftar otomatis dengan awalan `W4c`. Berkas ini memuat seluruh API komponen. Daftar halaman saja ada di `/llms.txt`. Keterangan halaman berbahasa Indonesia; komentar prop, event, dan slot dikutip apa adanya dari sumber komponen, yang ditulis dalam bahasa Inggris. ## Cara memakai - Pasang sebagai layer: `extends: ['@waste4change/ui']` di `nuxt.config.ts`, lalu `@import '@waste4change/ui'` di CSS utama. - Tailwind v4 saja, tanpa `tailwind.config.js`. Pakai token semantik (`bg-surface`, `text-content-muted`, utilitas `tone-*`), bukan warna mentah. - Radius hanya `rounded-control` (4px) dan `rounded-panel` (6px). - Warna dan ukuran lewat props (`color`, `variant`, `size`); `class` hanya untuk tata letak. - Teks bawaan berbahasa Indonesia dan bisa diganti lewat props. - `W4cToaster` dan `W4cConfirmDialog` dipasang sekali di `app.vue`, lalu dipanggil lewat `useToast()` dan `useConfirm()`. - Aturan keras dan daftar "pakai ini, bukan itu" ada di `node_modules/@waste4change/ui/AGENTS.md`. ## Komponen ### W4cAccordion Halaman: https://ui.w4c.id/components/accordion Bagian konten yang dapat dibuka dan ditutup. Props: - items?: W4cAccordionItem[] = [] — List of accordion items. - model-value?: string | string[] — Controlled open panel value (string or array of strings when multiple). - default-value?: string | string[] — Default open value when uncontrolled. - multiple?: boolean = false — Allow multiple panels to be open simultaneously. - variant?: W4cAccordionVariant = 'bordered' — Visual presentation of the accordion container and items. - size?: W4cAccordionSize = 'md' — Padding and typography sizing. Events: - update:modelValue: [value: string | string[]] - change: [value: string | string[]] Slots: - default - header { item: W4cAccordionItem isOpen: boolean toggle: () => void } - content { item: W4cAccordionItem } - icon { item: W4cAccordionItem; isOpen: boolean } - content-* ### W4cAlert Halaman: https://ui.w4c.id/components/alert Pesan status, peringatan, dan umpan balik kontekstual. v-model: - open: boolean = true Props: - color?: W4cAlertColor = 'primary' — Meaning of the message. `primary` is used for general information. - variant?: W4cAlertVariant = 'soft' - title?: string - description?: string - icon?: string | false — Iconify name. Defaults to an icon matching `color`; `false` hides it. - dismissible?: boolean = false — Show a close button. Closing sets `v-model:open` to false. - close-label?: string = 'Tutup' — Accessible name of the close button. Events: - close: [] Slots: - default - title - icon - actions ### W4cAppShell Halaman: https://ui.w4c.id/components/app-shell Sidebar, header, drawer HP, dan navigasi bawah dashboard. Props: - sections?: readonly W4cAppShellNavSection[] = [] - mobile-items?: readonly W4cAppShellNavItem[] — Optional dedicated bottom items. Defaults to the first mobile-enabled items. - mobile-limit?: number = 5 — Maximum default bottom items. Set zero to keep every item. - active?: W4cAppShellNavValue — Controlled active item. Without it, the current Nuxt route is used. - collapsed?: boolean — Controlled collapsed state for the desktop sidebar. - default-collapsed?: boolean = false - app-name?: string = 'Dashboard' - sidebar-label?: string = 'Navigasi utama' - mobile-label?: string = 'Navigasi utama seluler' - content-label?: string - skip-label?: string = 'Lewati ke konten' - collapse-label?: string = 'Ciutkan sidebar' - expand-label?: string = 'Perluas sidebar' - menu-label?: string = 'Buka menu' - close-menu-label?: string = 'Tutup menu' - content-as?: W4cAppShellContentTag = 'main' — Use div only when the shell is embedded inside an existing main landmark. - sticky-header?: boolean = true - show-mobile-navigation?: boolean = true - contained?: boolean = false — Fill a positioned parent instead of the browser viewport. Events: - update:collapsed: [value: boolean] - update:active: [value: W4cAppShellNavValue] - select: [item: W4cAppShellNavItem] Slots: - brand { collapsed: boolean } - item { item: W4cAppShellNavItem active: boolean collapsed: boolean surface: W4cAppShellSurface } - sidebar-footer { collapsed: boolean } - mobile-brand - header-start { collapsed: boolean; toggle: () => void } - header-end - default ### W4cAvatar Halaman: https://ui.w4c.id/components/avatar Foto, inisial, serta kelompok identitas pengguna. Props: - src?: string — Photo URL. Falls back to initials, and then to an icon, if it fails. - name?: string — Who or what this stands for: its initials and its accessible name. - initials?: string — Initials to draw instead of the ones taken from `name`. - icon?: string = 'lucide:user-round' — Iconify name used when there is neither a photo nor a name. - size?: W4cAvatarSize = 'md' - color?: W4cAvatarColor = 'neutral' — Tone of the fallback. `auto` picks one from the name, always the same. - square?: boolean = false — Rounded square instead of a circle: a company, a location, a vehicle. - label?: string — Accessible name. Defaults to `name`. Pass an empty string wherever the name is already written next to the avatar, which is most rows and cards: a screen reader would otherwise read it twice. ### W4cAvatarGroup Halaman: https://ui.w4c.id/components/avatar-group Beberapa orang pada satu baris, dengan sisanya jadi +N. Props: - items?: readonly W4cAvatarGroupItem[] = [] - size?: W4cAvatarSize = 'md' - max?: number — How many to draw before the rest collapse into one `+N` disc. Without it every item is drawn, which stops being readable past about six. - color?: W4cAvatarColor = 'auto' — Tone used by every item that does not carry its own. - square?: boolean = false — Rounded squares instead of circles, for companies or vehicles. - label?: string — What the group is, e.g. "Operator aktif". A group of people is one thing on the page, so it is named once instead of each face being named. - overflow-label?: string — Read out in place of `+N`. Defaults to "N lainnya". ### W4cBadge Halaman: https://ui.w4c.id/components/badge Label pendek untuk status, kategori, atau hitungan. Props: - color?: W4cBadgeColor = 'neutral' - variant?: W4cBadgeVariant = 'soft' - size?: W4cBadgeSize = 'md' - icon?: string — Decorative Iconify icon before the text. Takes precedence over dot. - dot?: boolean = false — Decorative status dot; always provide a text label as well. - rounded?: boolean = true — Pill shape; false uses the standard control radius. Slots: - default ### W4cBreadcrumb Halaman: https://ui.w4c.id/components/breadcrumb Jejak hierarki dari beranda menuju halaman aktif. Props: - items?: W4cBreadcrumbItem[] = [] — List of breadcrumb items from root to current page. - separator-icon?: string = 'lucide:chevron-right' — Iconify icon name for the separator. Defaults to chevron-right. - separator-text?: string — Text separator character (e.g. `/`), takes precedence over separatorIcon. - size?: W4cBreadcrumbSize = 'md' — Font size and spacing of the breadcrumb. - aria-label?: string = 'Breadcrumb' — Accessible label for the navigation landmark. Slots: - default - item { item: W4cBreadcrumbItem index: number isLast: boolean } - separator { index: number } ### W4cButton Halaman: https://ui.w4c.id/components/button Aksi utama, sekunder, tautan, ikon, dan loading. Props: - color?: W4cButtonColor = 'primary' - variant?: W4cButtonVariant = 'solid' - size?: W4cButtonSize = 'md' - type?: 'button' | 'submit' | 'reset' = 'button' — Defaults to `button` so a button inside a form never submits it by accident. - icon?: string — Iconify name shown before the label, e.g. `lucide:plus`. - trailing-icon?: string — Iconify name shown after the label. - loading?: boolean = false - disabled?: boolean = false - block?: boolean = false — Stretch to the full width of the container. - rounded?: boolean = false — Pill shape instead of the standard control radius. - to?: NuxtLinkProps['to'] — Render as a NuxtLink. Accepts internal routes and external URLs. Slots: - default - leading - trailing ### W4cCard Halaman: https://ui.w4c.id/components/card Wadah konten dengan header, body, dan footer. Props: - as?: 'div' | 'article' | 'section' = 'div' - variant?: W4cCardVariant = 'outline' - padding?: W4cCardPadding = 'md' — Applied independently to the header, body, and footer. - title?: string - description?: string - title-tag?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' = 'h3' — Match the surrounding page's heading hierarchy. Slots: - default - header - footer ### W4cCodeBlock Halaman: https://ui.w4c.id/components/code-block Kode berwarna dengan filename dan tombol salin. Props: - code: string - lang?: W4cCodeBlockLang = 'text' — Highlighting language. `text` renders the code without colours. - filename?: string — Shown in the top bar, e.g. a file path. Falls back to the language. - copyable?: boolean = true — Show the copy button. - copy-label?: string = 'Salin' - copied-label?: string = 'Tersalin' - flush?: boolean = false — Fill the panel around it edge to edge: no border and no rounded corners of its own. For a block that sits inside a panel which already draws those, where a second edge alongside the first reads as a double border. ### W4cCommandPalette Halaman: https://ui.w4c.id/components/command-palette Pencarian dan tindakan cepat dari satu dialog. v-model: - open: boolean = false Props: - items?: readonly W4cCommandPaletteItem[] = [] - shortcut?: string = 'mod+k' — Keyboard shortcut that opens it from anywhere, as `mod+k`. `mod` is ⌘ on Apple and Ctrl elsewhere. Empty turns the global shortcut off. - placeholder?: string = 'Cari…' - label?: string = 'Pencarian' — Accessible name of the dialog and of its search field. - close-label?: string = 'Tutup pencarian' - empty-title?: string = 'Tidak ada hasil' - empty-description?: string = 'Coba kata kunci lain.' - max?: number = 10 — Most rows drawn at once; the rest wait for a narrower search. - hints?: boolean = true — Show the row of keyboard hints along the bottom. - icon?: string = 'lucide:file-text' Events: - select: [item: W4cCommandPaletteItem] Slots: - trigger { open: () => void; shortcut: string } — The control that opens it. Without one, nothing is drawn until asked. - item { item: W4cCommandPaletteItem active: boolean index: number } - empty { query: string } - footer ### W4cConfirmDialog Halaman: https://ui.w4c.id/components/confirm-dialog Konfirmasi async untuk tindakan yang perlu keputusan. ### W4cCopyButton Halaman: https://ui.w4c.id/components/copy-button Tombol salin dengan konfirmasi yang terbacakan. Props: - value: string — Text put on the clipboard. - label?: string = 'Salin' — Label before copying. - copied-label?: string = 'Tersalin' - error-label?: string = 'Gagal menyalin' - icon-only?: boolean = false — Icon only, with the label as its accessible name. - icon?: string = 'lucide:copy' - copied-icon?: string = 'lucide:check' - color?: W4cButtonColor = 'neutral' - variant?: W4cButtonVariant = 'outline' - size?: W4cButtonSize = 'sm' - disabled?: boolean = false - reset-after?: number = 1600 — How long the copied or failed state stays, in milliseconds. Events: - copy: [value: string, ok: boolean] — After every attempt, so the page can show its own toast. ### W4cDescriptionList Halaman: https://ui.w4c.id/components/description-list Pasangan label dan nilai untuk halaman detail. Props: - items?: readonly W4cDescriptionListItem[] = [] - layout?: W4cDescriptionListLayout = 'stack' — `stack` puts the label above its value, `inline` beside it. - columns?: W4cDescriptionListColumns = 1 — Columns from the `sm` breakpoint up; a phone always shows one. - size?: W4cDescriptionListSize = 'md' - divided?: boolean = false — Rule between fields. - empty-text?: string = '—' — Shown where a value is empty, so a row is never silently blank. Slots: - value { item: W4cDescriptionListItem; index: number } — Replaces the value of every field. - value-* — Replaces the value of one field, by its key. ### W4cDraggable Halaman: https://ui.w4c.id/components/draggable Susun ulang item dengan pointer, sentuhan, atau keyboard. Props: - model-value?: W4cDraggableItem[] = [] - item-key?: string | ((item: W4cDraggableItem, index: number) => W4cDraggableKey) = 'id' - item-label?: string | ((item: W4cDraggableItem, index: number) => string) - item-disabled?: (item: W4cDraggableItem, index: number) => boolean - disabled?: boolean = false - size?: W4cDraggableSize = 'md' - variant?: W4cDraggableVariant = 'separated' - handle-label?: string = 'Ubah urutan' Events: - update:modelValue: [value: W4cDraggableItem[]] - reorder: [value: W4cReorderEvent] - dragStart: [item: W4cDraggableItem, index: number] - dragEnd: [item: W4cDraggableItem, index: number, cancelled: boolean] Slots: - item { item: W4cDraggableItem index: number dragging: boolean } - handle { item: W4cDraggableItem index: number dragging: boolean } ### W4cDrawer Halaman: https://ui.w4c.id/components/drawer Panel yang masuk dari tepi layar untuk detail dan filter. v-model: - modelValue: boolean = false Props: - title?: string — Heading of the panel. A drawer without one needs an `aria-label`. - description?: string — Line under the title, linked through aria-describedby. - side?: W4cDrawerSide = 'end' — Edge the panel comes from. `start` and `end` follow the writing direction, so a right-to-left layout mirrors them. - size?: W4cDrawerSize = 'md' — Width for a side panel, height for a top or bottom one. - dismissible?: boolean = true — Show the close button and let Escape close the panel. - close-label?: string = 'Tutup' - label?: string — Name of the panel, for when `#header` replaces the built-in one. Without it a replaced header leaves the dialog unnamed, and a screen reader announces it as just "dialog". - close-on-backdrop?: boolean = true — Let a click outside the panel close it. Events: - close: [] Slots: - default — Body of the panel. - header { close: () => void } — Replaces the whole header, including the close button. - title - description - footer { close: () => void } — Row of actions pinned under the body. `close` closes the panel. ### W4cDropdownMenu Halaman: https://ui.w4c.id/components/dropdown-menu Menu aksi dan tautan dengan navigasi keyboard. Props: - items: readonly W4cDropdownMenuItem[] - label?: string — Text on the built-in trigger. Leave it out for an icon-only button. - trigger-label?: string = 'Menu' — Accessible name for a trigger that shows only an icon. - align?: 'start' | 'end' = 'start' — Which edge of the trigger the menu lines up with. - disabled?: boolean = false - color?: W4cButtonColor = 'neutral' — Appearance of the built-in trigger, passed to W4cButton. - variant?: W4cButtonVariant = 'outline' - size?: W4cButtonSize = 'md' - icon?: string - trailing-icon?: string — Defaults to a chevron whenever the trigger has a visible label. Events: - select: [item: W4cDropdownMenuItem, index: number] - update:open: [value: boolean] Slots: - trigger { open: boolean attrs: Record toggle: () => void } — Replaces the built-in trigger. Bind `attrs` to your own control. - default — Label content of the built-in trigger. - item { item: W4cDropdownMenuItem; index: number } — Replaces the row content, for example with an avatar. ### W4cEmptyState Halaman: https://ui.w4c.id/components/empty-state Keadaan kosong dengan penjelasan dan tindakan berikutnya. Props: - title?: string = 'Belum ada data' - description?: string - icon?: string | false = 'lucide:inbox' — Iconify name; false hides the default illustration. - size?: W4cEmptyStateSize = 'md' - orientation?: 'vertical' | 'horizontal' = 'vertical' — Horizontal layout starts at the sm breakpoint; phones stay stacked. - title-tag?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'p' = 'h3' Slots: - icon - title - default - actions ### W4cFormCheckbox Halaman: https://ui.w4c.id/form/checkbox Pilihan boolean, array, dan status indeterminate. v-model: - modelValue: boolean | W4cFormChoiceValue[] = false Props: - id?: string — Standalone ID. Inside FormField, set the ID on FormField instead. - label?: string — Text next to the box. The default slot can hold richer content. - description?: string — Secondary line under the label, linked through aria-describedby. - value?: W4cFormChoiceValue — Value collected in the array when several checkboxes share a v-model. - size?: W4cFormControlSize = 'md' - indeterminate?: boolean = false — Neither checked nor unchecked, for a "select all" that is partly on. - disabled?: boolean = false - required?: boolean = false - invalid?: boolean = false Slots: - default - description ### W4cFormCurrency Halaman: https://ui.w4c.id/form/currency Nominal terformat dengan nilai model tetap numerik. v-model: - modelValue: number | null | undefined Props: - id?: string — Standalone ID. Inside FormField, set the ID on FormField instead. - currency?: string = 'IDR' — ISO code used for the symbol; the value stays a plain number. - locale?: string = 'id-ID' - prefix?: string | false — Overrides the symbol in front of the field. `false` hides it. - decimals?: number = 0 — Digits after the decimal separator. Rupiah is written without them. - allow-negative?: boolean = false — Allow amounts below zero, for corrections and refunds. - size?: W4cFormControlSize = 'md' - disabled?: boolean = false - readonly?: boolean = false - required?: boolean = false - invalid?: boolean = false - icon?: string ### W4cFormDatePicker Halaman: https://ui.w4c.id/form/date-picker Tanggal tunggal, rentang, serta tanggal dan waktu. v-model: - modelValue: string | string[] | undefined Props: - id?: string — Standalone ID. Inside FormField, set the ID on FormField instead. - type?: 'date' | 'datetime' | 'month' = 'date' — A plain calendar date, a date with a time of day, or a whole month. `month` keeps `YYYY-MM` in the model and shows it as "Oktober 2026". The value stays ISO so it sorts and parses the same way the dates do; formatting it for a reader is the application's job, as everywhere else. - range?: boolean = false — Pick two, and the value becomes `[start, end]`. Works with `month` too, where it is a span of months: `['2026-01', '2026-06']`. - size?: W4cFormControlSize = 'md' - min?: string — Earliest and latest date that can be chosen, as `YYYY-MM-DD`. - max?: string - locale?: string = 'id-ID' - first-day-of-week?: number = 1 — 1 is Monday, the way Indonesian calendars are printed; 0 is Sunday. - placeholder?: string - clearable?: boolean = true — Offer a button that empties the field. - disabled?: boolean = false - readonly?: boolean = false - required?: boolean = false - invalid?: boolean = false - open-label?: string = 'Buka kalender' - today-label?: string — Defaults to "Hari ini", or "Bulan ini" when `type` is `month`. - clear-label?: string — Defaults to "Hapus tanggal", or "Hapus bulan" when `type` is `month`. - done-label?: string = 'Selesai' - time-label?: string = 'Jam' ### W4cFormField Halaman: https://ui.w4c.id/form/field Label, hint, error, required, dan disabled bersama. Props: - id?: string — ID of the contained control, not of the field wrapper. - label?: string - hint?: string - error?: string — Validation is owned by the app; a non-empty error marks the control invalid. - required?: boolean = false - disabled?: boolean = false - group?: boolean = false — Show the label as a caption instead of a