@andreagiugni/tailwind-dashboard-ui
v0.5.17
Published
Reusable React + Tailwind CSS v4 dashboard components extracted from TailAdmin.
Readme
@andreagiugni/tailwind-dashboard-ui
Reusable React + Tailwind CSS v4 dashboard components extracted from TailAdmin. Every primitive
ships with its Tailwind styling, extends the underlying element's native HTML attributes (so
onClick, onDoubleClick, aria-*, data-*, … just work), exposes named style variants, and —
where visually meaningful — accepts inline bgColor / textColor / borderColor overrides.
Dual ESM + CJS builds with TypeScript types. Every component — including the data-viz widgets (charts, calendar, map) — is exported from the single package entry point.
Live preview
Explore every component with interactive previews, copy-ready snippets and complete prop references at taildashboardui.com.
Install
npm i @andreagiugni/tailwind-dashboard-uiPeer dependencies
The core package requires:
- React 18 or 19 (
react,react-dom) - Tailwind CSS v4 (
tailwindcss@^4)
clsx, tailwind-merge, and flatpickr (used by DatePicker) are bundled runtime dependencies —
you do not need to install them yourself.
The following heavy libraries are optional peers, only needed if you use the matching data-viz component:
| Component | Optional peer deps |
|---|---|
| BarChart, LineChart | apexcharts, react-apexcharts |
| Calendar | @fullcalendar/core, @fullcalendar/react, @fullcalendar/daygrid, @fullcalendar/timegrid, @fullcalendar/list, @fullcalendar/interaction |
| CountryMap | @react-jvectormap/core, @react-jvectormap/world |
| Editor (WYSIWYG) | @tiptap/react, @tiptap/pm, @tiptap/starter-kit, @tiptap/extension-link, @tiptap/extension-placeholder, @tiptap/extension-superscript, @tiptap/extension-subscript |
Install only the ones for the components you use, e.g.:
npm i apexcharts react-apexcharts # for BarChart / LineChart
npm i @tiptap/react @tiptap/pm @tiptap/starter-kit @tiptap/extension-link @tiptap/extension-placeholder @tiptap/extension-superscript @tiptap/extension-subscript # for EditorSSR note: the data-viz components and the
Editortouchwindow/the DOM at render time. In server-rendered frameworks (e.g. Next.js) render them client-only — for example withnext/dynamic(() => import('@andreagiugni/tailwind-dashboard-ui').then(m => m.BarChart), { ssr: false }). They are code-split into their own chunks and never executed unless you actually import them, so the rest of the library stays SSR-safe and light.
ColorPicker
The ColorPicker is built on react-beautiful-color,
which is a bundled dependency (installed automatically — you don't add it yourself). It is
client-only and code-split like the data-viz widgets, so render it client-only under SSR. It ships
its own stylesheet — import it once in your app:
import 'react-beautiful-color/dist/react-beautiful-color.css';Tailwind setup
The library ships its design tokens as an importable stylesheet. Add this line to your app's
Tailwind entry CSS (the file that already contains @import 'tailwindcss';):
@import '@andreagiugni/tailwind-dashboard-ui/theme.css';theme.css registers the full TailAdmin token set (brand / blue-light / gray / orange / success /
error / warning palettes, --text-theme-*, --shadow-theme-*, --z-index-*) inside an @theme
block, plus base layer rules.
Dark mode is driven by the .dark class. The theme defines a custom dark variant against an
ancestor .dark, so toggle dark mode by adding/removing the dark class on <html> (or any
ancestor):
<html class="dark">The ThemeToggleButton component is controllable for this purpose (theme + onToggle props).
Importing components
Everything is exported from the single package entry point:
import {
Button,
Badge,
Alert,
Input,
Select,
Modal,
Table,
TableHeader,
TableBody,
TableRow,
TableCell,
// hero-ui parity additions
Accordion,
AccordionItem,
Tabs,
Tab,
Tooltip,
Popover,
Drawer,
Chip,
Progress,
Spinner,
Skeleton,
Slider,
Code,
Snippet,
// data viz + editor (see SSR note above)
BarChart,
LineChart,
Calendar,
CountryMap,
Editor,
} from '@andreagiugni/tailwind-dashboard-ui';Props model
Three conventions apply across the library:
- Native handlers via HTML-attribute extension. Each component's props extend the root
element's React HTML attribute type (e.g.
ButtonHTMLAttributes), so every native handler and attribute (onClick,onDoubleClick,onMouseEnter,aria-*,data-*, …) is available with zero extra wiring and is forwarded onto the underlying element. - Named variants. Visual states are selected with discrete props such as
variant,size, andcolorinstead of class strings. - Inline color overrides. Where meaningful, components accept
bgColor,textColor, andborderColor. These map to inlinestyle(backgroundColor/color/borderColor) and let you escape the named palette for one-off colors. A consumer-suppliedstyleprop always wins.
import { Button, Badge } from '@andreagiugni/tailwind-dashboard-ui';
import '@andreagiugni/tailwind-dashboard-ui/theme.css'; // in your Tailwind entry CSS
<Button variant="primary" onDoubleClick={handle}>Save</Button>
<Button bgColor="#ff5722" textColor="#fff">Custom</Button>
<Badge color="success">Active</Badge>Component reference
Legend: (+native) = also extends the element's native HTML attributes.
(+override) = accepts bgColor / textColor / borderColor.
Core UI
| Component | Key props |
|---|---|
| Button | variant (primary/outline), size (sm/md), startIcon, endIcon, disabled, (+native button) (+override) |
| Badge | variant (light/solid), color (primary/success/error/warning/info/light/dark), size (sm/md), startIcon, endIcon, (+native span) (+override) |
| Ribbon | variant (corner/rounded/flag), color (primary/success/error/warning/info/dark), position (top-left/top-right/bottom-left/bottom-right), children (label), (+native span) (+override) — place inside a relative host (corner needs overflow-hidden) |
| Alert | variant (success/error/warning/info), title, message, showLink, linkHref, linkText, icon? (override icon), (+native div) |
| Avatar | src, alt, size (xsmall…xxlarge), status (online/offline/busy/none), statusColor?, (+native img) |
| AvatarText | children, className, (+native div) |
| Dropdown | isOpen, onClose, children, portal? (default true, prevents clipping inside tables/overflow containers), (+native div) |
| DropdownItem | variant (default/primary/outline, like Button), icon?, bgColor/textColor/borderColor overrides, tag (a/button), href, onClick, onItemClick, baseClassName (full override) |
| Modal | isOpen, onClose, title? (wrapping header aligned with close button), showCloseButton, isFullscreen, closeOnBackdrop?, closeOnEsc?; alert preset → variant (success/info/warning/danger) + title, description, actionText?, onAction?; (+native div) |
| Table (composable) | TableHeader / TableBody / TableRow / TableCell with children, isHeader (cell), (+native table elements; onClick / onDoubleClick on rows & cells) |
| Table (data-driven) | pass data + columns (key, header, sortable?, align?, render?, className?) to get search + three-state per-column sort (neutral/ascending/descending) + pagination: rowsPerPage? (max rows/page, default 10), rowsPerPageOptions?, searchKeys? (search box shown only when provided), searchPlaceholder?, defaultSortKey? / defaultSortDirection?, pagination?, paginationAlign? (left/center/right/full, default right), showSizeSelector?, onRowClick?, getRowId?, emptyContent? |
| Pagination | currentPage, totalPages, onPageChange, align? (left/center/right/full — full pins Previous/Next to the edges with page indices centered) |
| Breadcrumb | pageTitle, items?, (+native) |
| ThemeToggleButton | theme? (controlled), onToggle?, (+native button) |
| Card | title?, description?, icon?, image?, imageAlt?, horizontal?, footer?, children?, (+native div) (+override) |
| Accordion / AccordionItem | selectionMode (single/multiple), expandedKeys / defaultExpandedKeys, onExpandedChange; item: itemKey, title, startContent?, disabled |
| Tabs / Tab | variant (underline/solid/pill), selectedKey / defaultSelectedKey, onSelectionChange, color?; tab: tabKey, title, disabled |
| Chip | color, variant (light/solid), size, startIcon, endIcon, avatar?, onClose?, (+native span) (+override) |
| Code | color (primary/success/error/warning/info/default), size (sm/md), (+native code) (+override) |
| Snippet | code (string | string[]), symbol?, hideCopyButton?, hideSymbol?, size, (+override) |
| Progress | value, maxValue?, color, size (sm/md/lg), label?, showValueLabel?, isIndeterminate? |
| Spinner | size (sm/md/lg), color, label? |
| Skeleton | isLoaded, width?, height?, className, children? |
| Toast | variant (success/danger/warning/info), title, message?, icon?, hideIcon?, showCloseButton?, onClose?, hideAccentBar?, (+native div) (+override) |
Overlays
| Component | Key props |
|---|---|
| Tooltip | content, placement (top/right/bottom/left), delay?, disabled?, (+native span) (+override) |
| Popover | trigger, placement, isOpen? / defaultOpen? / onOpenChange?, closeOnOutsideClick?, closeOnEsc? |
| Drawer | isOpen, onClose, placement (left/right/top/bottom), showCloseButton?, closeOnBackdrop?, closeOnEsc?, size?, (+native div) |
Form controls
| Component | Key props |
|---|---|
| Input | type, value / defaultValue, onChange, success, error, hint, disabled, (+native input) (+override) |
| Label | htmlFor, children, (+native label) |
| Select | options ({ value, label, icon? }[]), placeholder, defaultValue, onChange(value), disabled |
| MultiSelect | options, selected / defaultSelected, onChange, placeholder, disabled |
| Checkbox | label, checked, onChange(checked), disabled, checkedColor? |
| Radio / RadioSm | id, name, value, checked, label, onChange(value), disabled |
| Switch | label, checked / defaultChecked, onChange(checked), color (blue/gray), disabled |
| TextArea | value, onChange, rows, success, error, hint, disabled |
| FileInput | onChange, accept, multiple, (+native input) |
| PasswordInput | password field with a show/hide eye toggle, (+native input attrs) |
| Dropzone | onDrop(files), accept?, multiple?, title?, description?, browseLabel? — drag-and-drop upload, dependency-free |
| DatePicker | id, mode (single/multiple/range/time), defaultDate, onChange, label, placeholder |
| DateTimePicker | id, label?, placeholder?, defaultDate?, defaultTime? ("HH:MM"), onChange?({ date, time }) — flatpickr date calendar + a compact HH:MM time input |
| Slider | value / defaultValue, onChange(value), min, max, step, color, label?, showValue?, disabled |
| ColorPicker | defaultValue? (hex), defaultFormat? / formats? (hex/rgb/rgba/hsl/hsla), showInput?, withEyeDropper?, label?, onChange?(value, color) — compact swatch + formatted value trigger opening a saturation/hue/alpha popup with a value input and format switcher; built on react-beautiful-color (bundled), client-only, import its CSS (see ColorPicker note above) |
| Editor (WYSIWYG) | content, onChange(html), placeholder?, editable?, toolbar? (ordered tool ids or custom buttons), editorClassName? — optional Tiptap peers; render client-only (see Data viz) |
Data viz
These wrap optional heavy peer deps and must be rendered client-only under SSR (see the SSR note in Peer dependencies).
| Component | Key props |
|---|---|
| BarChart | series, categories, colors?, height?, options? (merged over defaults) |
| LineChart | series, categories, colors?, height?, options? |
| Calendar | events, onEventClick, onDateSelect, initialView |
| CountryMap | markers, markerColor?, mapColor? |
| Editor (WYSIWYG) | content, onChange(html), placeholder?, editable?, toolbar? — Tiptap-powered, customizable toolbar |
The data-viz components default their data to sensible demo values, so they render out-of-the-box and are fully overridable via the props above.
The Editor is a Tiptap-powered rich-text editor with a fully customizable toolbar. Pass an
ordered toolbar array of built-in tool ids ("bold" | "italic" | "strike" | "code" |
"superscript" | "subscript" | "heading1" | "heading2" | "heading3" | "bulletList" |
"orderedList" | "blockquote" | "codeBlock" | "link" | "undo" | "redo" | "divider") or custom { id, icon, title, onClick,
isActive? } button objects. Set editable={false} for a read-only view (toolbar hidden).
import dynamic from 'next/dynamic';
const Editor = dynamic(
() => import('@andreagiugni/tailwind-dashboard-ui').then((m) => m.Editor),
{ ssr: false }
);
<Editor
content="<p>Hello <strong>world</strong></p>"
onChange={(html) => save(html)}
toolbar={['bold', 'italic', 'divider', 'bulletList', 'orderedList', 'link']}
/>Table
Table has two modes, both under the same component:
- Composable — use
Table/TableHeader/TableBody/TableRow/TableCellas thin, styled wrappers around the native table elements when you want full control over the markup. - Data-driven — pass a
dataarray and acolumnsdefinition and you get live search, per-column click-to-sort, a "Show N entries" selector and pagination out of the box. The mode switches on automatically as soon ascolumnsis provided.
import { Table, type TableColumn } from '@andreagiugni/tailwind-dashboard-ui';
type Person = { name: string; office: string; salary: number };
const people: Person[] = [
{ name: 'Abram Schleifer', office: 'Edinburgh', salary: 89500 },
{ name: 'Carla George', office: 'London', salary: 15500 },
// …
];
const columns: TableColumn<Person>[] = [
{ key: 'name', header: 'User', sortable: true },
{ key: 'office', header: 'Office', sortable: true },
{
key: 'salary',
header: 'Salary',
sortable: true,
align: 'right',
render: (row) => `$${row.salary.toLocaleString()}`, // custom cell
},
];
<Table
data={people}
columns={columns}
rowsPerPage={5} // max rows per page (default 10)
rowsPerPageOptions={[5, 10, 25]}
defaultSortKey="name"
searchKeys={['name', 'office']} // omit to hide the search box
onRowClick={(row) => console.log(row)}
/>Key data-driven props: data, columns (each: key, header, sortable?, align?, render?,
className?), rowsPerPage (default 10), rowsPerPageOptions (default [5,10,25,50]),
searchKeys / searchPlaceholder, defaultSortKey / defaultSortDirection, pagination,
paginationAlign (left / center / right / full, default right), showSizeSelector,
onRowClick, getRowId, emptyContent.
Search visibility: the search input renders only when you pass a non-empty
searchKeysarray — those are also the exact fields the query matches. OmitsearchKeys(or pass[]) to hide search entirely.
License
MIT © Andrea Giugni

