
Frutjam is a CSS-only UI component library for Tailwind CSS v4 that styles buttons, forms, navigation, dialogs, tabs, and other web elements.
It includes reusable classes and light and dark themes built on OKLCH color tokens.
Frutjam also works through an UnoCSS preset or a compiled stylesheet for plain HTML.
It also comes with JavaScript helpers for programmatic dialog controls, tabs, toasts, and searchable comboboxes.
Features
- 50+ CSS UI components for forms, layouts, feedback, and data display.
- CSS variables for OKLCH-based light, dark, and custom themes.
- Tailwind CSS v4 plugin with responsive variants and selective component loading.
- UnoCSS preset and a compiled stylesheet for projects outside Tailwind.
- Optional framework-independent JavaScript helpers for interactive components.
- React hooks for dialogs, drawers, tabs, carousels, notifications, and more.
- Component class prefixes and scoped theme tokens for CSS integration.
Use Cases
- Admin dashboards with navigation, forms, status labels, data tables, and dialogs.
- Server-rendered Django, Laravel Blade, or HTMX screens that use plain HTML classes.
- Content sites and marketing pages that need consistent headings, cards, buttons, and themes.
How To Use It
Installation
Install frutjam with NPM:
npm install -D frutjam
Import Tailwind CSS and register the Frutjam plugin in the stylesheet processed by Tailwind:
@import "tailwindcss"; @plugin "frutjam";
Basic Usage
Use Frutjam classes in regular HTML. Set a theme on a parent element. This card example has a labeled email input, a status badge, and a save button.
<section class="wrapper-md" data-theme="snowberry">
<div class="card card-outline">
<div class="card-content">
<h2 class="card-title">Workspace settings</h2>
<p class="para-base">Manage your team's workspace.</p>
<label for="team-email">Contact email</label>
<input id="team-email" type="email" class="input"
placeholder="[email protected]">
<div class="card-actions">
<button type="button" class="btn btn-primary">Save changes</button>
<span class="badge badge-success">Active</span>
</div>
</div>
</div>
</section>
Using Frutjam Without Tailwind CSS
The precompiled components bundle includes Frutjam’s base styles, default themes, components, and component utilities. It does not contain the general-purpose Tailwind utility library (flex, grid, p-4, etc.). Use standard CSS or your existing utility system for any additional layout styles.
For a bundler that accepts CSS imports:
import 'frutjam/css';
For a static HTML page, load the components-only CSS build. It does not include Tailwind utility classes. The @2 release selector follows version 2 updates; pin an exact release for production deployments.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/frutjam@2/dist/frutjam.components.css"> <button type="button" class="btn btn-primary">Save</button> <span class="badge badge-success">Published</span>
Including Tailwind Utilities Without a Build Step
The full Frutjam CSS distribution includes Tailwind’s general-purpose utilities as well as the component styles. Load this file when a static page needs classes such as flex, grid, and p-4.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/frutjam@2/dist/frutjam.min.css">
A bundler can import this file through frutjam/css/full:
import 'frutjam/css/full';
Using the UnoCSS Preset
Frutjam exposes presetFrutjam() for UnoCSS projects. Use UnoCSS 66 or newer and configure its Wind4 preset before loading Frutjam.
// uno.config.js
import { defineConfig, presetWind4 } from 'unocss';
import { presetFrutjam } from 'frutjam/unocss';
export default defineConfig({
presets: [presetWind4(), presetFrutjam()],
});
Interactive Combobox With Vanilla JavaScript
Use the optional JavaScript helper for a searchable combobox with keyboard navigation and selection events. The parent needs position: relative for its popup list. The following HTML uses Tailwind utility classes and a bundler that resolves frutjam/js.
<div id="framework-picker" class="relative w-64">
<label for="framework-search">Framework</label>
<input id="framework-search" class="input" type="text"
placeholder="Search frameworks">
<ul class="combobox-list" role="listbox">
<li class="combobox-item" role="option" data-value="react">React</li>
<li class="combobox-item" role="option" data-value="vue">Vue</li>
<li class="combobox-item" role="option" data-value="svelte">Svelte</li>
</ul>
</div>
import { createCombobox } from 'frutjam/js';
const picker = document.querySelector('#framework-picker');
createCombobox(picker);
picker.addEventListener('fj:select', (event) => {
console.log(event.detail.value);
});
Displaying Toast Notifications
A static toast container needs only CSS, but notifications created from application events use the optional toast manager. duration: 0 keeps the message in the container until it is dismissed.
<div id="messages" class="toast toast-top toast-end"></div>
import { createToastManager } from 'frutjam/js';
const messages = createToastManager(document.querySelector('#messages'));
messages.success('Settings saved', { duration: 3500 });
Tailwind Plugin Configuration Options
Pass Frutjam plugin settings through an @plugin block. include and exclude use comma-separated component identifiers. If include contains entries, it takes precedence over exclude.
@import "tailwindcss";
@plugin "frutjam" {
prefix: fj;
reset: false;
root: #admin;
include: button, card, alert, badge;
logs: false;
}
| Option | Default | Purpose |
|---|---|---|
prefix | "" | Prefix component class names, e.g. fj-btn. |
reset | true | Include Frutjam’s base element resets. |
root | :root | Scope theme tokens to :root, :host, or another selector. |
logs | true | Print Frutjam’s build-time console banner. |
include | [] | Include only the listed components and utilities. |
exclude | [] | Exclude the listed components and utilities. |
Class Prefixes With Tailwind
The Tailwind import prefix and Frutjam’s component prefix are independent. The first is a variant prefix, whereas the second changes Frutjam’s class names.
@import "tailwindcss" prefix(tw);
@plugin "frutjam" {
prefix: fj;
}
<button type="button" class="tw:fj-btn tw:fj-btn-primary"> Send message </button>
UnoCSS Preset Options
presetFrutjam() accepts these three options:
| Option | Default | Purpose |
|---|---|---|
preflight | true | Include Frutjam’s base styles and themes. |
prefix | "" | Prefix Frutjam component class names. |
layer | "frutjam" | Choose the CSS cascade layer for the preset. |
Themes And CSS Variables
Use data-theme on the root element or on any container. The package includes Snowberry (snowberry or light) and Darkberry (darkberry or dark). Other palettes require custom theme values.
<main data-theme="snowberry">
<section data-theme="darkberry">
<button class="btn btn-primary">Dark section</button>
</section>
</main>
Custom Themes
For custom themes, set the design tokens inside @layer theme. Choose foreground and background colors as matching pairs, and check contrast after changing the defaults.
@layer theme {
[data-theme="forest"] {
--scheme-color: dark;
--border-radius: 0.5rem;
--color-base: oklch(19% 0.03 155);
--color-on-base: oklch(96% 0.02 155);
--color-primary: oklch(72% 0.15 150);
--color-on-primary: oklch(16% 0.02 150);
}
}
Theme Token Reference
Root theme tokens use matching background and foreground color pairs. on-* variables supply the foreground colors.
| CSS Variable | Purpose |
|---|---|
--scheme-color | Light or dark color scheme. |
--border-radius | Base radius for Frutjam components. |
--color-base, --color-on-base | Page background and default text. |
--color-neutral, --color-on-neutral | Neutral surfaces and their foreground text. |
--color-primary, --color-on-primary | Primary color and contrasting content. |
--color-secondary, --color-on-secondary | Secondary color and contrasting content. |
--color-accent, --color-on-accent | Accent color and contrasting content. |
--color-info, --color-on-info | Informational color and contrasting content. |
--color-success, --color-on-success | Success color and contrasting content. |
--color-warning, --color-on-warning | Warning color and contrasting content. |
--color-error, --color-on-error | Error color and contrasting content. |
Generated Color Tokens
Each color role also has these generated tokens. {color} stands for base, neutral, primary, secondary, accent, info, success, warning, or error.
| Token | Purpose |
|---|---|
--color-{color}-50 | Lightest generated tint. |
--color-{color}-100 | Light tint. |
--color-{color}-200 | Light tint. |
--color-{color}-300 | Medium-light tint. |
--color-{color}-400 | Subtle tint. |
--color-{color}-500 | Base color. |
--color-{color}-600 | First darker shade. |
--color-{color}-700 | Medium-dark shade. |
--color-{color}-800 | Dark shade. |
--color-{color}-900 | Very dark shade. |
--color-{color}-950 | Darkest generated shade. |
--color-{color}-soft | Soft variant background. |
--color-on-{color}-soft | Foreground on a soft background. |
--color-{color}-active | Interactive active-state color. |
--color-body | Derived body text color. |
Color Utility Families
For {color} roles, Tailwind CSS utilities use the semantic theme colors. These are the color utility families.
| Class Pattern | Purpose |
|---|---|
bg-{color} | Background color. |
text-{color} | Text color. |
border-{color} | Border color. |
ring-{color} | Ring color. |
outline-{color} | Outline color. |
shadow-{color} | Shadow color. |
fill-{color} | SVG fill. |
stroke-{color} | SVG stroke. |
decoration-{color} | Text decoration. |
caret-{color} | Input caret. |
placeholder-{color} | Placeholder text. |
divide-{color} | Divider border color. |
Typography And Layout Classes
The complete wrapper width series is wrapper, wrapper-xs, wrapper-sm, wrapper-md, wrapper-lg, wrapper-xl, wrapper-2xl, and wrapper-full.
Heading and paragraph classes accept standard sizes and numeric pixel values, including heading-46 and para-28.
| Class Family | Values |
|---|---|
heading-{size} | xs, sm, md, base, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, 8xl, 9xl |
para-{size} | xs, sm, md, base, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, 8xl, 9xl |
prose prose-frutjam | Rich text styled with Frutjam theme tokens; requires @tailwindcss/typography. |
prose-invert | Inverted prose variant for dark backgrounds. |
Component CSS Class Reference
Frutjam CSS components use base classes plus modifiers for colors, sizes, layout, and state. The class inventory below includes their CSS utilities. Tailwind utility classes are configured through Tailwind itself.
Inputs & Forms
| Component | CSS Classes |
|---|---|
| Button | btn, btn-primary, btn-secondary, btn-accent, btn-info, btn-neutral, btn-success, btn-warning, btn-error, btn-square, btn-rounded, btn-pill, btn-circle, btn-xs, btn-sm, btn-md, btn-lg, btn-xl, btn-2xl, btn-wide, btn-block, btn-active, btn-disabled, btn-soft, btn-dashed, btn-outline, btn-ghost, btn-plain, btn-link |
| Checkbox | checkbox, checkbox-primary, checkbox-secondary, checkbox-accent, checkbox-info, checkbox-neutral, checkbox-success, checkbox-warning, checkbox-error, checkbox-circle, checkbox-rounded, checkbox-square, checkbox-xs, checkbox-sm, checkbox-md, checkbox-lg, checkbox-xl, checkbox-2xl, checkbox-disabled |
| Radio | radio, radio-primary, radio-secondary, radio-accent, radio-info, radio-neutral, radio-success, radio-warning, radio-error, radio-circle, radio-rounded, radio-square, radio-xs, radio-sm, radio-md, radio-lg, radio-xl, radio-2xl, radio-disabled |
| Toggle | toggle, toggle-primary, toggle-secondary, toggle-accent, toggle-neutral, toggle-info, toggle-success, toggle-warning, toggle-error, toggle-xs, toggle-sm, toggle-md, toggle-lg, toggle-xl |
| Input | input, input-primary, input-secondary, input-neutral, input-accent, input-info, input-success, input-warning, input-error, input-xs, input-sm, input-md, input-lg, input-xl, input-2xl, input-disabled, input-dashed, input-outline, input-soft, input-ghost, input-square |
| Textarea | textarea, textarea-primary, textarea-secondary, textarea-accent, textarea-neutral, textarea-info, textarea-success, textarea-warning, textarea-error, textarea-xs, textarea-sm, textarea-md, textarea-lg, textarea-xl, textarea-2xl, textarea-soft, textarea-ghost, textarea-dashed |
| Select | select, select-primary, select-secondary, select-neutral, select-accent, select-info, select-success, select-warning, select-error, select-xs, select-sm, select-md, select-lg, select-xl, select-2xl, select-soft, select-ghost, select-dashed |
| Range | range, range-primary, range-secondary, range-accent, range-neutral, range-info, range-success, range-warning, range-error, range-xs, range-sm, range-md, range-lg, range-xl |
| Rating | rating, rating-half, rate, rate-primary, rate-secondary, rate-accent, rate-neutral, rate-info, rate-success, rate-warning, rate-error, rating-xs, rating-sm, rating-md, rating-lg, rating-xl |
| Combobox | combobox-list, combobox-item, combobox-open, combobox-primary, combobox-secondary, combobox-accent, combobox-info, combobox-success, combobox-warning, combobox-error |
Layout & Navigation
| Component | CSS Classes |
|---|---|
| Navbar | navbar, navbar-start, navbar-center, navbar-end, navbar-top, navbar-middle, navbar-bottom, navbar-list |
| Sidebar | sidebar |
| Drawer | drawer, drawer-top, drawer-bottom, drawer-start, drawer-end, drawer-backdrop, drawer-content |
| Menu | menu, menu-horizontal, menu-vertical, menu-disabled, menu-active, menu-xs, menu-sm, menu-md, menu-lg, menu-xl, menu-title, menu-item |
| Breadcrumb | breadcrumb, breadcrumb-link, breadcrumb-current, breadcrumb-list, breadcrumb-item, breadcrumb-separator |
| Tabs | tabs, tab, tab-active, tab-disabled, tab-content, tabs-underline, tabs-box, tabs-bottom, tabs-lifted, tabs-end, tabs-vertical, tabs-xs, tabs-sm, tabs-md, tabs-lg, tabs-xl |
| Steps | steps, step, steps-horizontal, steps-vertical, step-primary, step-secondary, step-accent, step-neutral, step-info, step-success, step-warning, step-error |
| Footer | footer, footer-center, footer-title, footer-horizontal, footer-vertical |
| Header | header, header-sticky, header-fixed, header-shadow, header-blur, header-transparent, header-solid, header-sm, header-lg, header-content, header-start, header-center, header-end |
| Join | join, join-horizontal, join-vertical, join-item |
Feedback & Overlay
| Component | CSS Classes |
|---|---|
| Modal | modal, modal-slide-up, modal-slide-down, modal-slide-start, modal-slide-end, modal-start, modal-center, modal-end, modal-top, modal-middle, modal-bottom, modal-backdrop, modal-content |
| Toast | toast, toast-start, toast-center, toast-end, toast-top, toast-middle, toast-bottom |
| Alert | alert, alert-primary, alert-secondary, alert-accent, alert-info, alert-neutral, alert-success, alert-warning, alert-error, alert-dashed, alert-outline, alert-soft, alert-ghost, alert-rounded, alert-pill, alert-xs, alert-sm, alert-md, alert-lg, alert-horizontal, alert-vertical |
| Tooltip | tooltip, tooltip-primary, tooltip-secondary, tooltip-accent, tooltip-neutral, tooltip-info, tooltip-success, tooltip-warning, tooltip-error, tooltip-top, tooltip-bottom, tooltip-left, tooltip-right, tooltip-start, tooltip-end, tooltip-content |
| Popover | popover, popover-toggle, popover-content, popover-hover, popover-top-start, popover-top-center, popover-top-end, popover-end-top, popover-end-center, popover-end-bottom, popover-bottom-start, popover-bottom-center, popover-bottom-end, popover-start-top, popover-start-center, popover-start-bottom |
| Loading | loading, loading-base, loading-current, loading-primary, loading-secondary, loading-accent, loading-neutral, loading-info, loading-success, loading-warning, loading-error, loading-xs, loading-sm, loading-md, loading-lg, loading-xl, loading-dots, loading-bars |
| Skeleton | skeleton, skeleton-circle, skeleton-text |
| Progress | progress, progress-primary, progress-secondary, progress-accent, progress-info, progress-neutral, progress-success, progress-warning, progress-error |
| Radial Progress | radial-progress, radial-progress-base, radial-progress-current, radial-progress-primary, radial-progress-secondary, radial-progress-accent, radial-progress-neutral, radial-progress-info, radial-progress-success, radial-progress-warning, radial-progress-error, radial-progress-xs, radial-progress-sm, radial-progress-md, radial-progress-lg, radial-progress-xl |
Data Display
| Component | CSS Classes |
|---|---|
| Card | card, card-xs, card-sm, card-md, card-lg, card-xl, card-content, card-title, card-actions, card-link, card-outline, card-dashed, card-primary, card-secondary, card-accent, card-info, card-neutral, card-success, card-warning, card-error |
| Table | table, table-xs, table-sm, table-md, table-lg, table-xl, table-hover, table-zebra, table-zebra-rows, table-zebra-cols, table-pin-rows, table-pin-cols |
| Stat | stats, stat, stat-title, stat-value, stat-desc, stat-figure, stats-horizontal, stats-vertical, stat-primary, stat-secondary, stat-accent, stat-neutral, stat-info, stat-success, stat-warning, stat-error |
| Badge | badge, badge-primary, badge-secondary, badge-accent, badge-info, badge-neutral, badge-success, badge-warning, badge-error, badge-square, badge-rounded, badge-pill, badge-circle, badge-xs, badge-sm, badge-md, badge-lg, badge-xl, badge-2xl, badge-dashed, badge-outline, badge-soft, badge-ghost |
| Tag | tag, tag-remove, tag-primary, tag-secondary, tag-accent, tag-neutral, tag-info, tag-success, tag-warning, tag-error, tag-xs, tag-sm, tag-md, tag-lg, tag-xl, tag-soft, tag-outline, tag-square |
| Avatar | avatar, avatar-ring, avatar-online, avatar-offline, avatar-busy, avatar-away, avatar-group, avatar-primary, avatar-secondary, avatar-accent, avatar-info, avatar-neutral, avatar-success, avatar-warning, avatar-error, avatar-ring-primary, avatar-ring-secondary, avatar-ring-accent, avatar-ring-info, avatar-ring-neutral, avatar-ring-success, avatar-ring-warning, avatar-ring-error, avatar-xs, avatar-sm, avatar-md, avatar-lg, avatar-xl, avatar-2xl, avatar-circle, avatar-rounded, avatar-square |
| Indicator | indicator, indicator-item, indicator-start, indicator-end, indicator-center, indicator-top, indicator-middle, indicator-bottom |
| Status | status, status-primary, status-secondary, status-accent, status-neutral, status-info, status-success, status-warning, status-error, status-xs, status-sm, status-md, status-lg, status-xl |
| Diff | diff, diff-resizer, diff-item-1, diff-item-2 |
| Timeline | timeline, timeline-item, timeline-start, timeline-middle, timeline-end, timeline-vertical, timeline-horizontal, timeline-snap-start, timeline-snap-end, timeline-primary, timeline-secondary, timeline-accent, timeline-neutral, timeline-info, timeline-success, timeline-warning, timeline-error |
| Chat | chat, chat-start, chat-end, chat-avatar, chat-bubble, chat-header, chat-footer, chat-xs, chat-sm, chat-md, chat-lg, chat-xl, chat-bubble-primary, chat-bubble-secondary, chat-bubble-accent, chat-bubble-neutral, chat-bubble-info, chat-bubble-success, chat-bubble-warning, chat-bubble-error |
Typography & Decoration
| Component | CSS Classes |
|---|---|
| Hero | hero, hero-overlay, hero-content |
| Divider | divider, divider-primary, divider-secondary, divider-accent, divider-info, divider-neutral, divider-success, divider-warning, divider-error, divider-horizontal, divider-vertical, divider-start, divider-end, divider-solid, divider-dashed, divider-dotted |
| Kbd | kbd, kbd-xs, kbd-sm, kbd-md, kbd-lg, kbd-xl |
| Link | link, link-primary, link-secondary, link-accent, link-info, link-neutral, link-success, link-warning, link-error, link-xs, link-sm, link-md, link-lg, link-xl, link-2xl, link-hover |
| Mask | mask, mask-half-1, mask-half-2, mask-star, mask-star-2, mask-heart, mask-circle, mask-diamond, mask-squircle, mask-hexagon, mask-pentagon, mask-triangle |
| Swap | swap, swap-rotate, swap-flip |
| Countdown | countdown, countdown-xs, countdown-sm, countdown-md, countdown-lg, countdown-xl |
| Marquee | marquee, marquee-track, marquee-fade, marquee-pause, marquee-reverse, marquee-vertical, marquee-slow, marquee-normal, marquee-fast |
| Carousel | carousel, carousel-item, carousel-vertical, carousel-center, carousel-end |
| Accordion | accordion, accordion-content, accordion-flush |
| Collapsible | collapsible, collapsible-title, collapsible-content, collapsible-toggle, collapsible-arrow, is-collapsible-open, is-collapsible-close, collapsible-peek, collapsible-overlay, collapsible-group |
| Surface | surface, surface-1, surface-2, surface-rounded, surface-xs, surface-sm, surface-md, surface-lg, surface-xl, surface-outline, surface-dashed |
Vanilla JavaScript Helpers
Frutjam exports 8 optional DOM helpers from frutjam/js. The CSS components do not require a global initialization call. Use these functions when a page needs programmatic controls, searchable selection, or dynamic notifications.
| Export | Initializer And Methods |
|---|---|
createModal | createModal(dialogElement) returns open(), close(), toggle(), isOpen(). |
createDrawer | createDrawer(dialogElement) uses the modal helper methods. |
createCollapsible | createCollapsible(element) returns open(), close(), toggle(), isOpen(). |
createTooltip | createTooltip(element) returns show(), hide(), toggle(), isOpen(). |
createTabs | createTabs(tabsElement, panelsElement) returns activate(index), next(), prev(). |
createToastManager | createToastManager(containerElement) returns show(), success(), error(), warning(), info(), dismiss(element). |
createCarousel | createCarousel(element) returns goTo(index), next(), prev(), current(), count(). |
createCombobox | createCombobox(element) returns open(), close(), toggle(), filter(query). |
Toast Manager Options
For the Vanilla JS toast manager, show(message, { duration, type }) accepts duration (default 3000 milliseconds) and type (default an empty string). It returns the created alert element. success(message, options), error(message, options), warning(message, options), and info(message, options) specify the message type. Use dismiss(element) to remove a toast; duration: 0 disables timed removal.
JavaScript Helper Parameters
createTabs(tabsElement, panelsElement) accepts a tab list and an optional panel container. activate(index) uses a zero-based tab index. createCarousel(element).goTo(index) also uses a zero-based index and clamps it to available slides.
Combobox Selection Event
The combobox dispatches fj:select on its root when a selection is made. Listen on that root element; the custom event does not bubble. Its detail.value contains the selected item’s data-value or trimmed text.
React Hooks
React 18 or newer is required for the optional frutjam/react hooks. useToast().show() returns a toast ID; the Vanilla JS toast manager returns a DOM element. React toast options are duration (default 3000 milliseconds) and type (default an empty string).
| Hook | Primary Operation |
|---|---|
useModal() | ref, open(), close(), toggle(), isOpen(). |
useDrawer() | Alias of useModal(). Returns ref, open(), close(), toggle(), isOpen(). |
useCollapsible() | ref, open(), close(), toggle(), isOpen(). |
useTooltip() | ref, show(), hide(), toggle(), isOpen(). |
useTabs(initialIndex = 0) | active, activate(index), isActive(index), tablistProps, tabProps(index, count = 0), panelProps(index). |
useToast() | toasts, show(message, options), dismiss(id), success(), error(), warning(), info(). |
useCarousel() | ref, current, goTo(index), next(), prev(). |
useCombobox({ items = [], filterFn } = {}) | open, value, query, filtered, activeIndex, select(item), containerProps, inputProps, listboxProps, optionProps(item, index). |
Combobox Hook Filtering
useCombobox({ items, filterFn }) accepts an array of strings or objects with a label. A custom filterFn(items, query) can replace the default case-insensitive label filter.
All Frutjam UI Components
Inputs & Forms
Layout & Navigation
Feedback & Overlay
Data Display
Typography & Decoration
Cherry MCP Integration
Frutjam also has a separate Cherry MCP package for coding assistants. This integration supplies Frutjam component information to an MCP-capable editor. It is optional for building and running the UI.
{
"mcpServers": {
"frutjam": {
"command": "npx",
"args": ["-y", "frutjam-cherry"]
}
}
}
Alternatives & Related Resources
- Copy-Paste CSS Components Library for Modern Web – Open Props UI
- Lightweight & Semantic UI Component Library – Oat UI
- Modular UI Component Library – vrembem
- Modern UI Components with CSS and Vanilla JavaScript – SimpUI
- Accessible UI Component Library for Vanilla JS & React – Monochrome







