Use the tw-react-components library for building React UIs with TailwindCSS. Provides components (Button, Dialog, DataTable, Form controls, Layout, etc.), hooks (useToast, usePagination, useOutsideClick, etc.), and helpers. Use when building dashboards, forms, or UI features with this library.
Resources
1Install
npx skillscat add bacali95/tw-react-components/tw-react-components Install via the SkillsCat registry.
tw-react-components
React component library built with TailwindCSS for dashboards and applications.
Installation & Setup
# Using bun
bun add tw-react-components
# Using npm
npm install tw-react-components
# Using yarn
yarn add tw-react-components
# Using pnpm
pnpm add tw-react-componentstailwind.config.js:
module.exports = {
content: ['./node_modules/tw-react-components/**/*.{js,ts,jsx,tsx}'],
plugins: [
require('@tailwindcss/forms'),
require('tailwindcss-animate'),
require('tw-react-components/tailwindcss-plugin'),
],
};Import CSS:
@import 'tw-react-components/index.css';Core Types
type Size = 'small' | 'medium';
type Color = 'primary' | 'secondary' | 'slate' | 'gray' | 'red' | 'green' | 'blue' | /* ...all Tailwind colors */;Quick Reference
Button
import { Button } from 'tw-react-components';
<Button>Default</Button>
<Button variant="outlined" color="blue">Outlined</Button>
<Button prefixIcon={SaveIcon} loading>Saving...</Button>See references/components/button.md for full API.
Form Controls
Two patterns: FormInputs.* with react-hook-form, or standalone components.
// With react-hook-form
<FormProvider {...form}>
<FormInputs.Text name="username" label="Username" required />
<FormInputs.Select name="country" items={countries} search />
</FormProvider>
// Standalone
<TextInput value={text} onChange={(e) => setText(e.target.value)} />
<SelectInput items={items} value={selected} onChange={setSelected} />See references/components/form-controls.md for full API.
Dialog
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<Dialog.Trigger asChild><Button>Open</Button></Dialog.Trigger>
<Dialog.Content>
<Dialog.Title>Title</Dialog.Title>
<p>Content</p>
</Dialog.Content>
</Dialog>
<ConfirmDialog open={open} title="Delete?" onConfirm={handleDelete} onClose={close}>
Are you sure?
</ConfirmDialog>See references/components/dialog.md for FormDialog, PdfViewerDialog, etc.
DataTable
<DataTable
rows={data}
columns={{
id: { header: 'ID', field: 'id' },
name: { header: 'Name', field: 'name' },
}}
sorting={{ sorting, onSortingChange: setSorting }}
pagination={{ currentPage, setCurrentPage, totalItems, pageSize }}
actions={[
{ icon: EditIcon, onClick: handleEdit },
{ icon: TrashIcon, color: 'red', onClick: handleDelete },
]}
/>See references/components/data-table.md for full API.
Layout
<Layout
sidebarProps={{
items: [
{ type: 'item', pathname: '', title: 'Home', Icon: HomeIcon },
{ type: 'group', title: 'Admin', items: [...] },
],
}}
NavLink={NavLink}
useLocation={useLocation}
>
{children}
</Layout>See references/components/layout.md for full API.
Sheet
<Sheet open={isOpen} onOpenChange={setIsOpen}>
<Sheet.Content side="right">
<Sheet.Title>Title</Sheet.Title>
<div>Content</div>
</Sheet.Content>
</Sheet>See references/components/sheet.md for full API.
Tabs
<Tabs defaultValue="tab1">
<Tabs.List>
<Tabs.Trigger value="tab1">Tab 1</Tabs.Trigger>
<Tabs.Trigger value="tab2">Tab 2</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value="tab1">Content 1</Tabs.Content>
<Tabs.Content value="tab2">Content 2</Tabs.Content>
</Tabs>See references/components/tabs.md for full API.
Accordion
<Accordion type="single" collapsible>
<Accordion.Item value="item-1">
<Accordion.Trigger>Section 1</Accordion.Trigger>
<Accordion.Content>Content 1</Accordion.Content>
</Accordion.Item>
</Accordion>See references/components/accordion.md for full API.
DropdownMenu
<DropdownMenu>
<DropdownMenu.Trigger asChild>
<Button>Menu</Button>
</DropdownMenu.Trigger>
<DropdownMenu.Content>
<DropdownMenu.Item onClick={action}>
<DropdownMenu.Icon icon={UserIcon} />
Profile
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu>See references/components/dropdown-menu.md for submenus, checkboxes, radio groups.
Toast
// Setup: Add <Toaster /> to app root
const { toast } = useToast();
toast({ title: 'Saved!', variant: 'success' });
toast({ title: 'Error', variant: 'destructive', description: 'Failed to save.' });See references/components/toast.md for full API.
Other Components
| Component | Usage | Reference |
|---|---|---|
Tooltip |
<Tooltip content="Hint"><Button>Hover</Button></Tooltip> |
tooltip.md |
Popover |
Floating content relative to trigger | popover.md |
Badge |
<Badge color="green">Status</Badge> |
badge.md |
Spinner |
<Spinner /> or <Spinner fullScreen /> |
spinner.md |
Skeleton |
<Skeleton className="h-4 w-48" /> |
skeleton.md |
Separator |
<Separator orientation="vertical" /> |
separator.md |
Switch |
<Switch checked={on} onCheckedChange={setOn} /> |
switch.md |
Pagination |
Page navigation control | pagination.md |
ThemeSelector |
Light/dark mode toggle | theme-selector.md |
Hint |
Notification dots/badges | hint.md |
Flex |
Flexbox layout | flex.md |
Block |
Block container | block.md |
Card |
Container component | card.md |
Hooks
useToast
const { toast, dismiss } = useToast();
const { id, update } = toast({ title: 'Saving...' });
update({ title: 'Saved!', variant: 'success' });See references/hooks/use-toast.md for full API.
usePagination
const pages = usePagination(currentPage, totalPages);
// [1, 2, 3, '...', 10]useOutsideClick
const ref = useRef<HTMLDivElement>(null);
useOutsideClick(ref, () => setOpen(false));useIsMobile
const isMobile = useIsMobile(); // true if < 768pxOther Hooks
| Hook | Usage | Reference |
|---|---|---|
useOutsideClick |
Detect clicks outside element | use-outside-click.md |
useIsMobile |
Detect mobile viewport | use-is-mobile.md |
useDays |
Days for calendar grid | use-days.md |
useMonths |
Month names | use-months.md |
useLongPress |
Long press detection | use-long-press.md |
useOnSwipe |
Swipe gestures | use-on-swipe.md |
Helpers
import { cn, compareDates, getDisplayDate, isEmpty } from 'tw-react-components';
// Class merging
<div className={cn('base', condition && 'conditional')} />;
// Date formatting
getDisplayDate(new Date(), { format: 'LL' }); // "January 31, 2026"
// Comparison
compareDates(date1, date2); // -1, 0, or 1
// Empty check
isEmpty(null); // true
isEmpty(''); // true
isEmpty([]); // trueSee references/helpers.md for full API.
Common Patterns
Form with Validation
<FormInputs.Email
name="email"
label="Email"
required
validate={(value) => value.includes('@') || 'Invalid email'}
/>DataTable Custom Rendering
columns={{
status: {
header: 'Status',
field: 'status',
render: (item) => <Badge color={item.active ? 'green' : 'gray'}>{item.status}</Badge>,
},
}}Conditional DataTable Actions
actions={[
{ icon: TrashIcon, hide: (item) => !item.canDelete, onClick: handleDelete },
]}Resources
- Live demo: https://bacali95.github.io/tw-react-components
- Source:
libs/tw-react-components/src/
Reference Files
Components
- button.md
- dialog.md
- form-controls.md
- data-table.md
- layout.md
- tabs.md
- accordion.md
- dropdown-menu.md
- sheet.md
- tooltip.md
- popover.md
- toast.md
- badge.md
- spinner.md
- skeleton.md
- separator.md
- switch.md
- pagination.md
- theme-selector.md
- hint.md
- flex.md
- block.md
- card.md
Hooks
- use-toast.md
- use-pagination.md
- use-outside-click.md
- use-is-mobile.md
- use-days.md
- use-months.md
- use-long-press.md
- use-on-swipe.md