# Dreamtree UI

A comprehensive React + Tailwind CSS components library for building modern web applications. Built with accessibility, customization, and developer experience in mind.

## About the Company

Dreamtree UI is built and maintained under **[Dreamtree Global](http://dreamtreeglobal.com/)** — a team crafting thoughtful, accessible, developer-first software for the modern web. We believe great products start with a great foundation, and that's exactly what this design system aims to be: a polished, open, and dependable building block for teams everywhere.

🌐 **Website:** [dreamtreeglobal.com](http://dreamtreeglobal.com/)

## Author & Maintainer

**Partha Preetham Krishna M L**
📧 [preetham.krishna.dev@gmail.com](mailto:preetham.krishna.dev@gmail.com)

Have an idea, a bug, or just want to say hi? Reach out anytime — feedback from developers like you is what keeps this library growing.

## 💚 Sponsor & Support

Dreamtree UI is **free and open source**, built in the open and powered entirely by passion and late nights. Every component you use — every accessible button, dark-mode-ready table, and tree-shakeable export — represents hours of careful craft so that *your* product can ship faster and feel better.

If this library has saved you time, sparked an idea, or made your app a little more beautiful, please consider supporting its continued development. **Your sponsorship keeps the updates coming, the bugs squashed, and the docs sharp — for the whole community.** Even the smallest contribution is a huge encouragement. 🙏

### ☕ Make a one-tap donation via UPI

**📷 Scan the QR with any UPI app** (Google Pay, PhonePe, Paytm, BHIM, …) to pay instantly:

<p>
  <img src="https://unpkg.com/@dreamtree-org/twreact-ui@latest/doc/assets/upi-qr.png" alt="Scan to pay Dreamtree Global via UPI" width="220" height="220" />
</p>

> **UPI ID:** `dhrugantha.llp@kotak` &nbsp;•&nbsp; **Payee:** Dreamtree Global
>
> 📱 On mobile, you can also tap the button below — it opens your UPI app directly. On desktop, scan the QR above or copy the UPI ID into your payment app.

[![Pay via UPI](https://img.shields.io/badge/Pay-via%20UPI-22c55e?style=for-the-badge&logo=googlepay&logoColor=white)](upi://pay?pa=dhrugantha.llp@kotak&pn=Dreamtree%20Global&cu=INR&tn=Support%20Dreamtree%20UI)

### 🤝 Become a Sponsor

Want to back the project long-term or as a company? You can sponsor the package directly:

- 📦 **npm:** [`@dreamtree-org/twreact-ui`](https://www.npmjs.com/package/@dreamtree-org/twreact-ui) — star, share, and sponsor the package
- ✉️ **Corporate sponsorships & partnerships:** [preetham.krishna.dev@gmail.com](mailto:preetham.krishna.dev@gmail.com)

Every star ⭐, share, and contribution helps more than you know. Thank you for being part of the journey!

## Features

- 🎨 **Modern Design**: Clean, professional components with Tailwind CSS
- 🌙 **Dark Mode**: Built-in dark/light mode support
- ♿ **Accessible**: ARIA compliant with keyboard navigation
- 📱 **Responsive**: Mobile-first design approach
- 🎯 **TypeScript Ready**: Full TypeScript support
- 🧩 **Composable**: Flexible APIs with props, slots, and render functions
- 🎨 **Customizable**: Easy theming with Tailwind config
- 📦 **Tree Shakeable**: Import only what you need
- 🤖 **AI-native**: a companion [MCP server](#ai-agents-mcp-server) serves live prop contracts to coding agents

## Installation

```bash
npm install @dreamtree-org/twreact-ui
# or
yarn add @dreamtree-org/twreact-ui
```

## Quick Start

```jsx
import { Button, Input, Card } from '@dreamtree-org/twreact-ui';

function App() {
  return (
    <div className="p-4">
      <Card>
        <Card.Header>
          <Card.Title>Welcome to Dreamtree UI</Card.Title>
        </Card.Header>
        <Card.Content>
          <Input placeholder="Enter your name" />
          <Button className="mt-4">Get Started</Button>
        </Card.Content>
      </Card>
    </div>
  );
}
```

## AI agents (MCP server)

If you build UI with an AI coding agent (Claude Code, Cursor, …), wire up the
**[Model Context Protocol](https://modelcontextprotocol.io) server bundled in
this package**. It gives the agent live, queryable access to the library —
`list_components`, `get_component` (authoritative props/variants/sizes/examples
per component), `search_components`, the per-component docs as resources, and a
`compose_ui` prompt — so it stops guessing prop names.

Add it to your MCP client config (no extra install — it ships with the
library):

```jsonc
{
  "mcpServers": {
    "dreamtree-ui": {
      "command": "npx",
      "args": ["-y", "@dreamtree-org/twreact-ui", "mcp"]
    }
  }
}
```

The catalog is a build-time snapshot baked into the package, so the server is
self-contained (no source or network needed at runtime) and always matches the
library version you installed.

> The MCP server also serves the skill below as the `dreamtree://skill`
> resource, so MCP clients get it with **zero install**.

## AI assistant skill (file install)

If your assistant reads a project skill / rules file rather than MCP, install
the bundled skill into your repo with one command:

```bash
npx @dreamtree-org/twreact-ui init --ai claude
#                                    ^ claude | cursor | copilot | generic
```

| Provider  | Installs to |
| --------- | ----------- |
| `claude`  | `.claude/skills/dreamtree-ui/SKILL.md` |
| `cursor`  | `.cursor/rules/dreamtree-ui.mdc` |
| `copilot` | `.github/copilot-instructions.md` |
| `generic` | `ai-skills/dreamtree-ui.md` |

The skill primes the assistant on this library's components, the shared
variant/size/theming vocabulary, and the provider wiring. Add `--out <path>` to
choose a destination or `--force` to overwrite. Re-run after upgrading the
library to refresh it.

## Components

### Core Components

#### Button
Versatile button component with multiple variants and states.

**Props:**
- `variant`: 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'success' | 'warning' (default: 'primary')
- `size`: 'sm' | 'md' | 'lg' (default: 'md')
- `disabled`: boolean
- `loading`: boolean
- `leftIcon`: ReactNode
- `rightIcon`: ReactNode
- `fullWidth`: boolean
- `className`: string

```jsx
<Button variant="primary" size="lg" loading>
  Loading...
</Button>
```

#### Input
Enhanced text input with validation states, icons, and clear functionality.

**Props:**
- `type`: 'text' | 'password' | 'email' | 'search' | 'number' | 'tel' | 'url'
- `variant`: 'default' | 'filled' | 'outlined'
- `size`: 'sm' | 'md' | 'lg' (default: 'md')
- `label`: string
- `placeholder`: string
- `error`: string
- `success`: string
- `disabled`: boolean
- `required`: boolean
- `clearable`: boolean
- `icon`: ReactNode
- `iconPosition`: 'left' | 'right' (default: 'left')
- `showCount`: boolean
- `maxLength`: number
- `readOnly`: boolean
- `onClear`: () => void

```jsx
<Input
  type="email"
  label="Email Address"
  placeholder="Enter your email"
  error="Please enter a valid email"
  clearable
  required
/>
```

#### Select
Advanced select component with search, multi-select, and grouping support.

**Props:**
- `options`: Array<{value: any, label: string, disabled?: boolean}>
- `value`: any | Array<any>
- `onChange`: (value: any) => void
- `placeholder`: string (default: 'Select an option...')
- `label`: string
- `error`: string
- `disabled`: boolean
- `required`: boolean
- `multiSelect`: boolean
- `searchable`: boolean
- `grouped`: boolean
- `creatable`: boolean
- `onCreateOption`: (value: string) => void
- `onSearch`: (term: string) => void
- `loading`: boolean
- `selectAllOption`: boolean
- `closeOnSelect`: boolean
- `maxTagCount`: number (default: 3)
- `allowClear`: boolean

```jsx
<Select
  options={[
    { value: 'us', label: 'United States' },
    { value: 'ca', label: 'Canada' }
  ]}
  multiSelect
  searchable
  placeholder="Choose countries"
/>
```

#### Form
Declarative form builder with validation support.

**Props:**
- `fields`: Array<FormField>
- `onSubmit`: (data: any) => void
- `defaultValues`: object
- `validationSchema`: any
- `submitText`: string (default: 'Submit')
- `resetText`: string (default: 'Reset')
- `showReset`: boolean (default: true)

```jsx
const formFields = [
  {
    type: 'text',
    name: 'firstName',
    label: 'First Name',
    required: true,
    placeholder: 'Enter your first name'
  },
  {
    type: 'email',
    name: 'email',
    label: 'Email',
    required: true
  }
];

<Form
  fields={formFields}
  onSubmit={(data) => console.log(data)}
  submitText="Create Account"
/>
```

#### Table
Feature-rich data table with sorting, filtering, and pagination.

**Props:**
- `data`: Array<object>
- `columns`: Array<Column>
- `sortable`: boolean (default: true)
- `filterable`: boolean
- `selectable`: boolean
- `pagination`: boolean
- `pageSize`: number (default: 10)
- `onSort`: (key: string, direction: 'asc' | 'desc') => void
- `onFilter`: (filters: object) => void
- `onSelectionChange`: (selectedRows: Set<any>) => void
- `onRowClick`: (row: object) => void
- `hasDetails`: boolean
- `DetailsComponent`: ReactComponent
- `withAction`: boolean
- `onAction`: (action: string, row: object) => void
- `actions`: Array<Action>
- `showSerial`: boolean (default: true)

```jsx
const columns = [
  { key: 'name', label: 'Name', sortable: true },
  { key: 'email', label: 'Email', sortable: true },
  { key: 'role', label: 'Role' }
];

<Table
  columns={columns}
  data={users}
  sortable
  filterable
  pagination
  pageSize={10}
/>
```

#### DatePicker
Calendar-based date selection with keyboard navigation.

**Props:**
- `value`: Date | string
- `onChange`: (date: Date | null) => void
- `placeholder`: string (default: 'Select date...')
- `label`: string
- `error`: string
- `disabled`: boolean
- `required`: boolean
- `minDate`: Date | string
- `maxDate`: Date | string
- `weekStartsOn`: 0 | 1 (default: 0)
- `portal`: boolean
- `displayFormat`: string (default: 'MMM dd, yyyy')
- `locale`: Locale
- `showClear`: boolean (default: true)
- `closeOnSelect`: boolean (default: true)

```jsx
<DatePicker
  label="Birth Date"
  minDate={new Date('1900-01-01')}
  maxDate={new Date()}
  placeholder="Select your birth date"
/>
```

### Navigation Components

#### Sidebar
Collapsible sidebar navigation with nested items.

**Props:**
- `items`: Array<SidebarItem>
- `collapsed`: boolean (default: false)
- `onToggle`: () => void
- `logo`: ReactNode
- `user`: {name: string, email: string, avatar?: string, menuItems?: Array<MenuItem>}
- `onUserClick`: (user: object) => void

```jsx
const sidebarItems = [
  {
    id: 'dashboard',
    label: 'Dashboard',
    icon: <Home className="h-4 w-4" />,
    active: true
  },
  {
    id: 'users',
    label: 'Users',
    icon: <Users className="h-4 w-4" />,
    children: [
      { id: 'all-users', label: 'All Users' },
      { id: 'new-user', label: 'Add New User' }
    ]
  }
];

<Sidebar
  items={sidebarItems}
  logo={<div className="text-xl font-bold">Dreamtree</div>}
  user={{ name: 'John Doe', email: 'john@example.com' }}
/>
```

#### Navbar
Top navigation bar with user menu and notifications.

**Props:**
- `logo`: ReactNode
- `items`: Array<NavItem>
- `user`: {name: string, email: string, avatar?: string, menuItems?: Array<MenuItem>}
- `notifications`: Array<Notification>
- `searchable`: boolean
- `onSearch`: (term: string) => void
- `onNotificationClick`: (notifications: Array<Notification>) => void
- `onUserClick`: (user: object) => void
- `leftIcon`: ReactNode | false
- `onLeftIconClick`: () => void

```jsx
<Navbar
  logo={<div className="text-xl font-bold">Dreamtree</div>}
  items={navItems}
  user={user}
  notifications={notifications}
  searchable
  onSearch={(term) => console.log(term)}
/>
```

### Feedback Components

#### Alert
Status messages and notifications with different variants.

**Props:**
- `variant`: 'success' | 'error' | 'warning' | 'info' (default: 'info')
- `title`: string
- `children`: ReactNode
- `dismissible`: boolean
- `onDismiss`: () => void

```jsx
<Alert variant="success" title="Success!" dismissible>
  Your changes have been saved successfully.
</Alert>
```

#### Toast
Notification messages with different types and positions.

**Props:**
- `id`: string
- `title`: string
- `message`: string
- `type`: 'success' | 'error' | 'warning' | 'info' (default: 'info')
- `duration`: number (default: 5000)
- `onClose`: (id: string) => void
- `position`: 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center'

```jsx
import { useToast, ToastContainer } from 'dreamtree-ui';

function App() {
  const { toast, toasts, removeToast } = useToast();

  const showSuccess = () => {
    toast.success('Success!', 'Your changes have been saved.');
  };

  return (
    <div>
      <button onClick={showSuccess}>Show Success</button>
      <ToastContainer toasts={toasts} onRemove={removeToast} />
    </div>
  );
}
```

### Utility Components

#### Card
Content containers with header, body, and footer sections.

**Props:**
- `children`: ReactNode
- `hover`: boolean
- `className`: string

```jsx
<Card hover>
  <Card.Header>
    <Card.Title>Card Title</Card.Title>
    <Card.Description>Card description</Card.Description>
  </Card.Header>
  <Card.Content>
    Card content goes here
  </Card.Content>
  <Card.Footer>
    <Button>Action</Button>
  </Card.Footer>
</Card>
```

#### Avatar
User profile images with fallbacks and status indicators.

**Props:**
- `src`: string
- `alt`: string
- `name`: string
- `size`: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default: 'md')
- `shape`: 'circle' | 'square' | 'rounded' (default: 'circle')
- `status`: 'online' | 'offline' | 'away' | 'busy'

```jsx
<Avatar
  src="https://example.com/avatar.jpg"
  name="John Doe"
  size="lg"
  status="online"
/>
```

#### Badge
Status indicators and labels with different variants.

**Props:**
- `children`: ReactNode
- `variant`: 'default' | 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'outline' (default: 'default')
- `size`: 'sm' | 'md' | 'lg' (default: 'md')
- `rounded`: boolean (default: true)

```jsx
<Badge variant="success" size="sm">
  Active
</Badge>
```

#### Tabs
Tabbed content organization with different styles.

**Props:**
- `items`: Array<{id: string, label: string, content: ReactNode, icon?: ReactNode, badge?: string}>
- `defaultActiveTab`: string
- `orientation`: 'horizontal' | 'vertical' (default: 'horizontal')
- `variant`: 'default' | 'pills' | 'underline' (default: 'default')
- `onTabChange`: (tabId: string) => void

```jsx
const tabItems = [
  {
    id: 'overview',
    label: 'Overview',
    content: <div>Overview content</div>
  },
  {
    id: 'settings',
    label: 'Settings',
    content: <div>Settings content</div>
  }
];

<Tabs items={tabItems} variant="pills" />
```

## Theming

Dreamtree UI supports custom theming through Tailwind CSS configuration:

```js
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: {
          50: '#eff6ff',
          100: '#dbeafe',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
        },
        success: {
          50: '#f0fdf4',
          100: '#dcfce7',
          500: '#22c55e',
          600: '#16a34a',
        },
        error: {
          50: '#fef2f2',
          100: '#fee2e2',
          500: '#ef4444',
          600: '#dc2626',
        },
        warning: {
          50: '#fffbeb',
          100: '#fef3c7',
          500: '#f59e0b',
          600: '#d97706',
        }
      }
    }
  }
}
```

## Dark Mode

Enable dark mode with the built-in theme provider:

```jsx
import { ThemeProvider } from 'dreamtree-ui';

function App() {
  return (
    <ThemeProvider defaultTheme="dark">
      {/* Your app content */}
    </ThemeProvider>
  );
}
```

## Examples

### Complete Form Example

```jsx
import { Form, Button, Card } from 'dreamtree-ui';

const formFields = [
  {
    type: 'text',
    name: 'firstName',
    label: 'First Name',
    required: true,
    placeholder: 'Enter your first name'
  },
  {
    type: 'email',
    name: 'email',
    label: 'Email',
    required: true,
    placeholder: 'Enter your email'
  },
  {
    type: 'select',
    name: 'country',
    label: 'Country',
    options: [
      { value: 'us', label: 'United States' },
      { value: 'ca', label: 'Canada' }
    ]
  }
];

function ContactForm() {
  const handleSubmit = (data) => {
    console.log('Form data:', data);
  };

  return (
    <Card>
      <Card.Header>
        <Card.Title>Contact Information</Card.Title>
        <Card.Description>Please fill out the form below</Card.Description>
      </Card.Header>
      <Card.Content>
    <Form
      fields={formFields}
      onSubmit={handleSubmit}
      submitText="Send Message"
    />
      </Card.Content>
    </Card>
  );
}
```

### Data Table with Actions

```jsx
import { Table, Button, Badge } from 'dreamtree-ui';

const columns = [
  { key: 'name', label: 'Name', sortable: true },
  { key: 'email', label: 'Email', sortable: true },
  { key: 'status', label: 'Status' }
];

const data = [
  { 
    id: 1, 
    name: 'John Doe', 
    email: 'john@example.com', 
    status: 'Active' 
  },
  { 
    id: 2, 
    name: 'Jane Smith', 
    email: 'jane@example.com', 
    status: 'Inactive' 
  }
];

const actions = [
  {
    label: 'Edit',
    onClick: (row) => console.log('Edit', row)
  },
  {
    label: 'Delete',
    onClick: (row) => console.log('Delete', row),
    variant: 'destructive'
  }
];

function UserTable() {
  return (
    <Table
      columns={columns}
      data={data}
      sortable
      filterable
      pagination
      pageSize={10}
      actions={actions}
    />
  );
}
```

## Contributing

We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.

## License

MIT License - see [LICENSE](LICENSE) for details.

## Support

- 📖 [Documentation](https://dreamtree-ui.dev)
- 🐛 [Issue Tracker](https://github.com/dreamtree-ui/dreamtree-ui/issues)
- 💬 [Discussions](https://github.com/dreamtree-ui/dreamtree-ui/discussions)
- 🌐 [Dreamtree Global](http://dreamtreeglobal.com/)
- 📧 [preetham.krishna.dev@gmail.com](mailto:preetham.krishna.dev@gmail.com)