npm package: @marcoschwartz/lite-ui
Description: A lightweight UI component library built with Tailwind CSS
Author: Marco Schwartz
Latest version: 0.27.11

# Lite UI

A lightweight, modern UI component library built with React, TypeScript, and Tailwind CSS v4.

## ✨ Features

- 🎨 **21 Production-Ready Components** - From basic inputs to complex data tables
- 🌙 **Dark Mode Support** - Built-in dark mode with system preference detection
- 🎭 **Theming System** - Multiple themes with easy customization
- 📦 **Tree-Shakeable** - Only bundle what you use (ESM & CJS)
- ⚡ **TypeScript First** - Full type safety and IntelliSense support
- 🚀 **Server Component Compatible** - Works with Next.js App Router and RSC
- 🎯 **Zero Runtime CSS** - Styles compiled with Tailwind CSS v4
- ♿ **Accessible** - ARIA-compliant components

## 📦 Installation

```bash
npm install @marcoschwartz/lite-ui
```

### Setup for Next.js (Required)

> ⚠️ **Important:** You must include `ColorSchemeScript` in your layout to prevent dark mode flashing (FOUC).

```tsx
// app/layout.tsx
import { ThemeProvider, ColorSchemeScript } from '@marcoschwartz/lite-ui';
import '@marcoschwartz/lite-ui/styles.css';

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <head>
        <ColorSchemeScript defaultColorMode="system" />
      </head>
      <body>
        <ThemeProvider defaultTheme="default" defaultColorMode="system">
          {children}
        </ThemeProvider>
      </body>
    </html>
  );
}
```

**Key points:**
- `ColorSchemeScript` must be in `<head>` - it prevents flash by setting colors before React hydrates
- `suppressHydrationWarning` on `<html>` is required to avoid React warnings
- `defaultColorMode` should match between `ColorSchemeScript` and `ThemeProvider`

### Setup for Vite/Other React Apps

```tsx
// main.tsx
import '@marcoschwartz/lite-ui/styles.css';
import { ThemeProvider } from '@marcoschwartz/lite-ui';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <ThemeProvider defaultTheme="default" defaultColorMode="system">
    <App />
  </ThemeProvider>
);
```

For Vite apps, add the theme script to your `index.html`:

```html
<head>
  <script>
    (function(){try{var d=document.documentElement,c=localStorage.getItem('lite-ui-color-mode')||'system',r=c;if(c==='system'||!c)r=matchMedia('(prefers-color-scheme:dark)').matches?'dark':'light';d.setAttribute('data-color-mode',r);d.style.colorScheme=r;if(r==='dark'){d.classList.add('dark');d.style.backgroundColor='hsl(0,0%,3.9%)';d.style.color='hsl(0,0%,98%)'}else{d.classList.remove('dark');d.style.backgroundColor='hsl(0,0%,100%)';d.style.color='hsl(0,0%,3.9%)'}}catch(e){}})();
  </script>
</head>
```

### Start using components:

```tsx
import { Button, Card, TextInput } from '@marcoschwartz/lite-ui';

export default function Page() {
  return (
    <Card>
      <h1>Welcome to Lite UI</h1>
      <TextInput placeholder="Enter your name" />
      <Button variant="primary">Submit</Button>
    </Card>
  );
}
```

## 🎨 Components

### Form Controls
- **Button** - Versatile button with 6 variants and 4 sizes
- **TextInput** - Text input with validation and error states
- **Select** - Dropdown select with custom styling
- **Checkbox** - Checkbox with label and error support
- **Toggle** - Switch/toggle component with multiple sizes
- **DatePicker** - Date selection input
- **TimePicker** - Time selection input
- **DateTimePicker** - Combined date and time picker

### Layout & Navigation
- **AppShell** - Complete app layout with header, navbar, aside, and footer
- **Navbar** - Responsive navigation bar
- **Sidebar** - Collapsible sidebar with mobile support
- **SidebarNav** - Collapsible navigation with icon-only mode and tooltips
- **Drawer** - Slide-out drawer panel
- **Modal** - Accessible modal dialog
- **Tabs** - Tabbed navigation component

### Feedback & Overlays
- **Alert** - Alert messages with 4 variants
- **Spinner** - Loading spinner with 3 sizes
- **Badge** - Status badges with 6 variants

### Data Display
- **Card** - Content container with optional header/footer
- **Table** - Data table with sorting and selection
- **Pagination** - Page navigation component

### Utilities
- **ActionMenu** - Dropdown action menu
- **Icons** - Set of common UI icons

[**📖 View Full Component Documentation**](./COMPONENTS.md)

## 🌙 Dark Mode

Lite UI includes built-in dark mode support with three color modes.

### Preventing Flash (FOUC)

To prevent the flash of wrong colors on page load, you **must** use `ColorSchemeScript`:

```tsx
// app/layout.tsx
import { ColorSchemeScript, ThemeProvider } from '@marcoschwartz/lite-ui';

<html lang="en" suppressHydrationWarning>
  <head>
    <ColorSchemeScript defaultColorMode="system" />
  </head>
  <body>
    <ThemeProvider defaultColorMode="system">
      {children}
    </ThemeProvider>
  </body>
</html>
```

### Toggling Dark Mode

```tsx
import { useTheme } from '@marcoschwartz/lite-ui';

function ThemeToggle() {
  const { colorMode, setColorMode } = useTheme();

  return (
    <select value={colorMode} onChange={(e) => setColorMode(e.target.value)}>
      <option value="system">System</option>
      <option value="light">Light</option>
      <option value="dark">Dark</option>
    </select>
  );
}
```

## ⬆️ Upgrading from v0.24.7 or earlier

If you're upgrading from an earlier version, update your `layout.tsx`:

```diff
- import { ThemeProvider, themeScript } from '@marcoschwartz/lite-ui';
+ import { ThemeProvider, ColorSchemeScript } from '@marcoschwartz/lite-ui';

  <html lang="en" suppressHydrationWarning>
    <head>
-     <script
-       dangerouslySetInnerHTML={{ __html: themeScript }}
-       suppressHydrationWarning
-     />
+     <ColorSchemeScript defaultColorMode="system" />
    </head>
```

The new `ColorSchemeScript` component:
- Sets CSS custom properties inline (prevents flash even if CSS loads slowly)
- Cleaner API than the old `themeScript` string
- Supports `nonce` prop for Content Security Policy

## 🎭 Theming

Switch between built-in themes or create your own:

```tsx
import { useTheme } from '@marcoschwartz/lite-ui';

function ThemeSwitcher() {
  const { themeName, setTheme } = useTheme();

  return (
    <div>
      <button onClick={() => setTheme('default')}>Default Theme</button>
      <button onClick={() => setTheme('minimalistic')}>Minimalistic Theme</button>
    </div>
  );
}
```

### Available Themes

- **Default** - Vibrant colors, shadows, and smooth animations
- **Minimalistic** - Flat design, subtle colors, minimal effects

## 🚀 Usage Examples

### Basic Form

```tsx
"use client";

import { useState } from 'react';
import { Card, TextInput, Button, Alert } from '@marcoschwartz/lite-ui';

export function ContactForm() {
  const [email, setEmail] = useState('');
  const [submitted, setSubmitted] = useState(false);

  return (
    <Card>
      <h2>Contact Us</h2>
      {submitted && (
        <Alert variant="success">Message sent successfully!</Alert>
      )}
      <TextInput
        label="Email"
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="your@email.com"
      />
      <Button
        variant="primary"
        onClick={() => setSubmitted(true)}
      >
        Send Message
      </Button>
    </Card>
  );
}
```

### Data Table

```tsx
import { Table } from '@marcoschwartz/lite-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' },
];

export function UserTable() {
  return (
    <Table
      columns={columns}
      data={data}
      sortable
      selectable
    />
  );
}
```

### Modal Dialog

```tsx
"use client";

import { useState } from 'react';
import { Modal, Button } from '@marcoschwartz/lite-ui';

export function ConfirmDialog() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Open Dialog</Button>
      <Modal
        isOpen={isOpen}
        onClose={() => setIsOpen(false)}
        title="Confirm Action"
      >
        <p>Are you sure you want to proceed?</p>
        <div className="flex gap-2 mt-4">
          <Button variant="danger" onClick={() => setIsOpen(false)}>
            Confirm
          </Button>
          <Button variant="secondary" onClick={() => setIsOpen(false)}>
            Cancel
          </Button>
        </div>
      </Modal>
    </>
  );
}
```

### Collapsible Sidebar Navigation

```tsx
"use client";

import { useState } from 'react';
import {
  AppShell,
  SidebarNav,
  SidebarNavItem,
  SidebarNavSection,
  SidebarNavDivider,
  SidebarNavCollapseToggle,
  HomeIcon,
  UserIcon,
  SettingsIcon,
} from '@marcoschwartz/lite-ui';

export function DashboardLayout({ children }) {
  const [activeItem, setActiveItem] = useState('dashboard');
  const [navbarWidth, setNavbarWidth] = useState<number | undefined>();

  return (
    <AppShell
      title="My App"
      navbar={{
        content: (
          <SidebarNav
            collapsible
            onCollapseChange={(_, width) => setNavbarWidth(width)}
          >
            <SidebarNavSection grow>
              <SidebarNavItem
                icon={<HomeIcon size="sm" />}
                label="Dashboard"
                active={activeItem === 'dashboard'}
                onClick={() => setActiveItem('dashboard')}
              />
              <SidebarNavItem
                icon={<UserIcon size="sm" />}
                label="Users"
                active={activeItem === 'users'}
                onClick={() => setActiveItem('users')}
              />
              <SidebarNavItem
                icon={<SettingsIcon size="sm" />}
                label="Settings"
                active={activeItem === 'settings'}
                onClick={() => setActiveItem('settings')}
              />
            </SidebarNavSection>
            <SidebarNavDivider />
            <SidebarNavCollapseToggle />
          </SidebarNav>
        ),
        width: navbarWidth, // Dynamic width from SidebarNav
      }}
    >
      {children}
    </AppShell>
  );
}
```

**SidebarNav Features:**
- **Collapsible mode** - Toggle between full and icon-only view
- **Tooltips** - Show labels on hover when collapsed
- **Persistent state** - Collapse state saved to localStorage
- **Smooth transitions** - Animated width changes
- **Mantine-compatible API** - Use `leftSection` as alias for `icon`

## 🛠️ Development

### Running the Demo

```bash
# Clone the repository
git clone https://github.com/marcoschwartz/lite-ui.git
cd lite-ui-js

# Install dependencies
npm install

# Run library + demo app in watch mode
npm run dev:all
```

This will:
1. Start the library build in watch mode (auto-rebuilds on changes)
2. Start the Next.js demo app on http://localhost:3000
3. Hot-reload changes from the library in the demo app

### Building

```bash
# Build library
npm run build

# Build CSS only
npm run build:css
```

## 📂 Project Structure

```
lite-ui-js/
├── src/                    # Library source code
│   ├── components/         # React components
│   ├── theme/             # Theme system
│   ├── icons/             # Icon components
│   └── index.ts           # Main exports
├── demo/                  # Demo Next.js app
│   └── app/
│       ├── components/    # Component examples
│       └── page.tsx       # Home page
├── dist/                  # Built library (generated)
└── package.json
```

## 🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## 📄 License

MIT © Marco Schwartz

## 🔗 Links

- [NPM Package](https://www.npmjs.com/package/@marcoschwartz/lite-ui)
- [GitHub Repository](https://github.com/marcoschwartz/lite-ui)
- [Component Documentation](./COMPONENTS.md)

## 💡 Technology Stack

- **React 19** - UI framework
- **TypeScript 5** - Type safety
- **Tailwind CSS v4** - Utility-first styling
- **tsup** - TypeScript bundler
- **Next.js 15** - Demo app framework