107 lines
2.4 KiB
Markdown
107 lines
2.4 KiB
Markdown
|
|
# Base UI Tailwind Components
|
||
|
|
|
||
|
|
Source-owned React components built on `@base-ui/react` and styled with Tailwind CSS.
|
||
|
|
|
||
|
|
This repository is intentionally source-only. Copy the component folders you need into an internal app and adjust the Tailwind classes locally, the same way you would with shadcn/ui.
|
||
|
|
|
||
|
|
## Install Dependencies
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npm install @base-ui/react clsx tailwind-merge lucide-react
|
||
|
|
```
|
||
|
|
|
||
|
|
## Required Helper
|
||
|
|
|
||
|
|
Copy `lib/utils.ts` with the components:
|
||
|
|
|
||
|
|
```ts
|
||
|
|
import { clsx, type ClassValue } from "clsx"
|
||
|
|
import { twMerge } from "tailwind-merge"
|
||
|
|
|
||
|
|
export function cn(...inputs: ClassValue[]) {
|
||
|
|
return twMerge(clsx(inputs))
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Import Styles
|
||
|
|
|
||
|
|
Default imports expose styled Base UI-style namespaces:
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
import Dialog from "@/components/ui/dialog"
|
||
|
|
|
||
|
|
<Dialog.Root>
|
||
|
|
<Dialog.Trigger>Open</Dialog.Trigger>
|
||
|
|
<Dialog.Portal>
|
||
|
|
<Dialog.Backdrop />
|
||
|
|
<Dialog.Popup>
|
||
|
|
<Dialog.Title>Title</Dialog.Title>
|
||
|
|
<Dialog.Description>Description</Dialog.Description>
|
||
|
|
<Dialog.Close>Close</Dialog.Close>
|
||
|
|
</Dialog.Popup>
|
||
|
|
</Dialog.Portal>
|
||
|
|
</Dialog.Root>
|
||
|
|
```
|
||
|
|
|
||
|
|
Named imports expose shadcn-style components:
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
import {
|
||
|
|
Dialog,
|
||
|
|
DialogContent,
|
||
|
|
DialogTitle,
|
||
|
|
DialogTrigger,
|
||
|
|
} from "@/components/ui/dialog"
|
||
|
|
|
||
|
|
<Dialog>
|
||
|
|
<DialogTrigger>Open</DialogTrigger>
|
||
|
|
<DialogContent>
|
||
|
|
<DialogTitle>Title</DialogTitle>
|
||
|
|
</DialogContent>
|
||
|
|
</Dialog>
|
||
|
|
```
|
||
|
|
|
||
|
|
Single-part components support both habits:
|
||
|
|
|
||
|
|
```tsx
|
||
|
|
import Button from "@/components/ui/button"
|
||
|
|
import { Button as UIButton } from "@/components/ui/button"
|
||
|
|
|
||
|
|
<Button>Default import</Button>
|
||
|
|
<UIButton>Named import</UIButton>
|
||
|
|
```
|
||
|
|
|
||
|
|
## Component Shape
|
||
|
|
|
||
|
|
Every component is a folder under `components/ui`. Composite components split Base UI parts into separate files:
|
||
|
|
|
||
|
|
```txt
|
||
|
|
components/ui/dialog/
|
||
|
|
index.ts
|
||
|
|
root.tsx
|
||
|
|
trigger.tsx
|
||
|
|
portal.tsx
|
||
|
|
backdrop.tsx
|
||
|
|
popup.tsx
|
||
|
|
title.tsx
|
||
|
|
description.tsx
|
||
|
|
close.tsx
|
||
|
|
content.tsx
|
||
|
|
```
|
||
|
|
|
||
|
|
`index.ts` assembles the default namespace export and the named shadcn-style exports.
|
||
|
|
|
||
|
|
## Styling
|
||
|
|
|
||
|
|
Styles use static Tailwind class strings so Tailwind can scan them. Every styled part accepts `className`; custom classes are merged after defaults with `cn()`.
|
||
|
|
|
||
|
|
The default visual direction follows the Base UI examples: neutral surfaces, clear borders, compact controls, `focus-visible` outlines, and Base UI `data-*` attributes for state styling.
|
||
|
|
|
||
|
|
## Validate
|
||
|
|
|
||
|
|
```bash
|
||
|
|
npm run check
|
||
|
|
```
|
||
|
|
|
||
|
|
This runs TypeScript and verifies that every planned component folder has an `index.ts` with a default export.
|