frappe-ui
Build UIs that look and feel like Frappe products by composing frappe-ui components and styling with the library's semantic Tailwind tokens.
Quick start
<script setup>
import { Button, Dialog, FormControl } from 'frappe-ui'
import { ref } from 'vue'
const open = ref(false)
const name = ref('')
</script>
<template>
<div class="p-4 bg-surface-base text-ink-gray-8">
<Button variant="solid" theme="gray" @click="open = true">New Task</Button>
<Dialog v-model:open="open" title="Create Task">
<FormControl v-model="name" label="Title" required />
</Dialog>
</div>
</template>
Where to look
Prop names, prop value types, slot names and token names live in these files, not here. Open the one you need before you write markup.
| Writing this | Open this first |
|---|---|
| any component, any page, any Tailwind class | CORE.md |
| anything that fetches or writes data | DATA.md |
| a fresh Vite + Vue 3 project | SETUP.md |
Contracts
These hold across components. Everything else is per-component, and lives in CORE.md.
- Pick the component. Every interactive element comes from
CORE.md. Raw HTML is for layout: grids, flex, spacing wrappers. - Color is two props:
variantandtheme. The value sets differ per component —CORE.mdlists each one. In your own markup, colors come from the semantic scales:bg-surface-*,text-ink-*,border-outline-*. - Two-way state is
v-model. Inputs takev-model. Overlays takev-model:open.ComboboxandMultiSelectadd optionalv-model:query.Listaddsv-model:selectionandv-model:active. - Icons are CSS classes.
<span class="lucide-edit size-4" aria-hidden="true" />. A prop namedicontakes the string"lucide-edit". - Slot names are per component, never universal. Read the component's
entry in
CORE.mdbefore writing a<template #…>. - Frappe API calls go through the
use*composables —useCall,useList,useDoc,useDoctype,useNewDoc, all exported fromfrappe-ui. Each one takes its own option set and returns its own shape; DATA.md lists them separately.