Lua Design System - A React component library for Lua applications
npm install luaniverseLua Design System - A React component library for Lua applications


``bash`
npm install @lua-global/luaniverseor
yarn add @lua-global/luaniverseor
pnpm add @lua-global/luaniverse
`tsx`
import { Button, IconButton, Badge, Textarea } from '@lua-global/luaniverse';
import { UserIcon, Trash, PDF, PNG, Chat, Clock, Minus, Plus, Tag } from '@lua-global/luaniverse';
Import the CSS file in your app's entry point:
`tsx`
import '@lua-global/luaniverse/styles';
Available Exports:
- @lua-ai-global/luaniverse - Components and utilities@lua-ai-global/luaniverse/styles
- - CSS styles and design tokens @lua-ai-global/luaniverse/tailwind
- - Tailwind preset for utility classes
> 💡 Quick Setup: See INTEGRATION.md for step-by-step consumer app setup instructions.
⚠️ IMPORTANT: Luaniverse requires BOTH the Tailwind preset AND the styles to work correctly. Missing either will cause components to lose their backgrounds and styling.
#### Step 1: Add the Tailwind Preset
Update your tailwind.config.js to use the Luaniverse preset:
`js
// tailwind.config.js
import { luaniversePreset } from '@lua-ai-global/luaniverse/tailwind';
export default {
presets: [luaniversePreset], // 🔥 Required for component styling
content: [
// Your content paths
'./src/*/.{js,jsx,ts,tsx}',
'./app/*/.{js,jsx,ts,tsx}',
// 🔥 Required: Include luaniverse components for class detection
'./node_modules/@lua-ai-global/luaniverse/*/.{js,jsx,ts,tsx}',
],
// Your additional config...
};
`
Or with CommonJS:
`js
// tailwind.config.js
const { luaniversePreset } = require('@lua-ai-global/luaniverse/tailwind');
module.exports = {
presets: [luaniversePreset],
content: [
'./src/*/.{js,jsx,ts,tsx}',
'./node_modules/@lua-ai-global/luaniverse/*/.{js,jsx,ts,tsx}',
],
};
`
#### Step 2: Import the Styles
In your main CSS file, import the Luaniverse styles:
`css`
/ app.css or globals.css /
@import '@lua-ai-global/luaniverse/styles'; / 🔥 Required for design tokens /
@import 'tailwindcss';
#### Why Both Are Required
- Preset: Enables utility classes like bg-popover, text-card-foreground--primary
- Styles: Provides CSS variables (, --popover) and typography system
❌ Without preset: Components lose backgrounds (transparent dropdowns)
❌ Without styles: Components lose design tokens and typography
✅ With both: Components work perfectly!
Luaniverse comes with built-in dark mode support. The library uses Tailwind's class-based dark mode strategy.
#### Enabling Dark Mode
To enable dark mode in your application:
1. Add the dark class to your HTML:
`html`
2. Or toggle it programmatically:
`tsx
// Toggle dark mode
document.documentElement.classList.toggle('dark');
// Enable dark mode
document.documentElement.classList.add('dark');
// Disable dark mode
document.documentElement.classList.remove('dark');
`
3. With React state management:
`tsx`
function App() {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
document.documentElement.classList.toggle('dark', darkMode);
}, [darkMode]);
return (
{/ Your app content /}
);
}
#### Dark Mode Features
- Automatic Color Adaptation - All components automatically adapt their colors for dark mode
- Maintained Accessibility - Focus indicators and contrast ratios remain WCAG compliant in dark mode
- Brand Consistency - Primary and destructive colors maintain brand identity across themes
- Smooth Transitions - Built-in CSS transitions for theme switching
Problem: Dropdown menus, cards, or other components appear transparent or unstyled.
Cause: Missing Tailwind preset or incomplete setup.
Solution: Ensure you have both parts of the setup:
1. ✅ Preset added to tailwind.config.js./node_modules/@lua-ai-global/luaniverse/*/.{js,jsx,ts,tsx}
2. ✅ Styles imported in your CSS
3. ✅ Content paths include
`js
// ✅ Correct setup
import { luaniversePreset } from '@lua-ai-global/luaniverse/tailwind';
export default {
presets: [luaniversePreset], // Enables bg-popover, bg-card utilities
content: [
'./src/*/.{js,jsx,ts,tsx}',
'./node_modules/@lua-ai-global/luaniverse/*/.{js,jsx,ts,tsx}', // Required!
],
};
`
`css`
/ ✅ Required in your CSS /
@import '@lua-ai-global/luaniverse/styles';
@import 'tailwindcss';
Problem: Custom typography classes like text-h1, link-primary don't work.
Solution: Make sure you've imported the styles (they contain custom @utility definitions).
Problem: Build fails with Tailwind-related errors.
Solution: Check that your content paths are correct and that you're using a compatible Tailwind version (v3.3+ or v4+).
A versatile button component with multiple variants, sizes, and states.
`tsx
import { Button } from '@lua-global/luaniverse';
function App() {
return (
#### Button Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
variant | 'default' \| 'primary' \| 'outline-solid' \| 'tertiary' \| 'secondary' \| 'muted' \| 'destructive' | 'default' | The visual style variant |
| size | 'small' \| 'default' \| 'large' | 'default' | The size of the button |
| loading | boolean | false | Shows loading spinner when true |
| disabled | boolean | false | Disables the button |
| asChild | boolean | false | Render as a child element |
| startAdornment | React.ReactNode | - | Icon or element before the text |
| endAdornment | React.ReactNode | - | Icon or element after the text |
| aria-label | string | - | Accessible label for the button |
| aria-describedby | string | - | Additional description for complex actions |#### Button Variants
- default: Black background with white text (adapts to white background in dark mode)
- primary: Blue background with white text
- outline: White background with blue border and text
- tertiary: White background with gray border (adapts to dark gray in dark mode)
- secondary: Gray background using CSS variables
- muted: Transparent background with hover states
- destructive: Red background with white text
#### Button Examples
`tsx
// With Luaniverse icons
import { UserIcon, Camera } from '@lua-global/luaniverse';}>
Profile
}>
Take Photo
// Loading state
// As a link
`$3
A button component designed specifically for icons with proper accessibility features and sizing.
`tsx
import { IconButton } from '@lua-global/luaniverse';
import { UserIcon, Trash, XIcon } from '@lua-global/luaniverse';function App() {
return (
);
}
`#### IconButton Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
variant | 'default' \| 'primary' \| 'outline-solid' \| 'tertiary' \| 'secondary' \| 'muted' \| 'destructive' | 'default' | The visual style variant |
| size | 'small' \| 'default' \| 'large' | 'default' | The size of the button |
| loading | boolean | false | Shows loading spinner when true |
| disabled | boolean | false | Disables the button |
| asChild | boolean | false | Render as a child element |
| aria-label | string | Required | Accessible label describing the action |
| aria-describedby | string | - | Additional description for complex actions |#### IconButton Sizes
- small: 28px × 28px button with 16px recommended icon size
- default: 40px × 40px button with 20px recommended icon size
- large: 48px × 48px button with 24px recommended icon size
#### IconButton Examples
`tsx
import { IconButton } from '@lua-global/luaniverse';
import { UserIcon, Trash, Camera, ArrowLeft } from '@lua-global/luaniverse';// Navigation
// Actions
// Destructive actions
// Loading state
// Different sizes
`$3
A flexible badge component for displaying status, counts, and labels with multiple variants and color options.
`tsx
import { Badge } from '@lua-global/luaniverse';function App() {
return (
Default
Secondary
Error
Outline
Success
Warning
);
}
`#### Badge Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
variant | 'default' \| 'secondary' \| 'destructive' \| 'outline-solid' \| 'success' \| 'warning' | 'default' | The visual style variant |
| asChild | boolean | false | Render as a child element |
| aria-label | string | - | Accessible label for the badge |#### Badge Variants
- default: Primary color background with white text
- secondary: Gray background using CSS variables
- destructive: Red background for errors and warnings
- outline: Transparent background with border
- success: Green background for positive status
- warning: Yellow background for cautionary information
#### Badge Examples
`tsx
// Status badges
Active
Error
Pending // Count badges
3
New
// As a link
5 unread
`$3
A multi-line text input component with built-in label, description, error states, and accessibility features.
`tsx
import { Textarea } from '@lua-global/luaniverse';function App() {
return (
label="Message"
placeholder="Enter your message..."
/>
label="Feedback"
description="Please provide detailed feedback"
error="This field is required"
/>
);
}
`#### Textarea Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
label | string | - | Label text displayed above the textarea |
| description | string | - | Helper text displayed below the textarea |
| error | string | - | Error message displayed below the textarea |
| success | string | - | Success message displayed below the textarea |
| resize | 'none' \| 'vertical' \| 'horizontal' \| 'both' | 'vertical' | Resize behavior |
| disabled | boolean | false | Disables the textarea |
| aria-describedby | string | - | Additional description references |
| aria-invalid | boolean | - | Indicates validation state |#### Textarea Examples
`tsx
// Basic textarea
label="Comments"
placeholder="Add your comments..."
/>// With description
label="Bio"
description="Tell us about yourself (max 500 characters)"
placeholder="Write your bio..."
/>
// Error state
label="Required Field"
error="This field is required"
placeholder="Please enter text..."
/>
// Success state
label="Feedback"
success="Thank you for your feedback!"
value="Great product!"
/>
// Disabled state
label="Read Only"
disabled
value="This content cannot be edited"
/>
// Custom resize behavior
label="Notes"
resize="both"
placeholder="Resize me in any direction..."
/>
`Icons
Luaniverse includes a comprehensive collection of icons for Lua applications.
$3
Standard icons inherit their parent's text color by default, making them work properly with different backgrounds and themes.
`tsx
import {
ArrowLeft, ArrowUp, Camera, Chat, Clock, ImageIcon, Logo, MapPin,
Microphone, Minus, Paperclip, PaperPlane, PaperPlaneTilt, Plus,
RecordIcon, SignOut, Tag, Trash, UserIcon, VideoCamera, XIcon
} from '@lua-global/luaniverse';function App() {
return (
);
}
`#### Available Standard Icons
- ArrowLeft - Left-pointing arrow for navigation
- ArrowUp - Up-pointing arrow for navigation
- Camera - Camera icon for photo actions
- Chat - Chat/message icon for communication
- Clock - Clock icon for time and scheduling
- ImageIcon - Generic image icon
- Logo - Lua logo
- MapPin - Location/map pin icon
- Microphone - Microphone for audio recording
- Minus - Minus/remove icon for actions
- Paperclip - Attachment icon
- PaperPlane - Send/paper plane icon
- PaperPlaneTilt - Tilted paper plane variant
- Plus - Plus/add icon for actions
- RecordIcon - Recording indicator
- SignOut - Sign out/logout icon
- Tag - Tag/label icon for categorization
- Trash - Delete/trash icon
- UserIcon - User profile icon
- VideoCamera - Video camera icon
- XIcon - Close/cancel icon
$3
File icons maintain their recognizable brand colors for easy file type identification.
`tsx
import {
PDF, PNG, JPG, MP4, MP3, DOC, XLS, PPT, Zip, CSS, JS, JSON,
HTML, SVG, AI, PSD, Fig, Sketch
} from '@lua-global/luaniverse';function FileList() {
return (
);
}
`#### Available File Icons
Images: PDF, PNG, JPG, SVG, AI, PSD, Fig, Sketch
Documents: DOC, XLS, PPT
Media: MP4, MP3
Code: CSS, JS, JSON, HTML
Archives: Zip
$3
All icons accept these common props:
| Prop | Type | Default | Description |
|------|------|---------|-------------|
|
size | number | 24 | The size of the icon in pixels |
| color | string | "currentColor" | The color of the icon (standard icons only) |
| aria-label | string | - | Accessible label for the icon |
| aria-describedby | string | - | Additional description |
| aria-hidden | boolean | - | Hide from screen readers (for decorative icons) |
| title | string | - | Tooltip text that appears on hover |$3
Icons are designed with accessibility in mind and include default aria-labels based on their names:
`tsx
// Automatic aria-label (aria-label="User")
// Custom aria-label overrides the default
// Icons with tooltips
// Decorative icons in buttons (button provides the label)
// Default aria-labels for common icons:
{/ aria-label="Close" /}
{/ aria-label="Arrow left" /}
{/ aria-label="Send" /}
{/ aria-label="Search" /}
{/ aria-label="Plus" /}
{/ aria-label="Minus" /}
`#### Default Aria-Labels
Standard icons automatically get meaningful aria-labels:
- XIcon → "Close"
- ArrowLeft → "Arrow left"
- PaperPlane → "Send"
- MagnifyingGlass → "Search"
- UserIcon → "User"
- Plus/Minus → "Plus"/"Minus"
- And many more based on component names
This improves accessibility out of the box while still allowing customization.
Development
$3
- Node.js >= 18
- pnpm >= 8
$3
`bash
Install dependencies
pnpm installStart development
pnpm devBuild library
pnpm buildRun Storybook
pnpm storybook
`$3
The library is built with tsup for optimal bundling:
- ESM:
dist/index.mjs
- CJS: dist/index.js
- Types: dist/index.d.ts
- Styles: dist/styles.css$3
The library is fully tree-shakable. Import only what you need:
`tsx
// ✅ Tree-shakable - only Button and UserIcon are bundled
import { Button, UserIcon } from '@lua-global/luaniverse';// ❌ Imports everything
import * as Luaniverse from '@lua-global/luaniverse';
`Accessibility
Luaniverse components are built with accessibility as a priority:
- WCAG AA Compliance - All components meet accessibility standards
- Keyboard Navigation - Full keyboard support with proper focus management
- Screen Reader Support - Proper ARIA labels and descriptions
- High Contrast - Works with high contrast modes and themes
- Development Warnings - Console warnings for missing accessibility attributes in development
$3
`tsx
// ✅ Good - Descriptive labels
// ✅ Good - Additional context
aria-label="Delete"
aria-describedby="delete-description"
>
// ❌ Bad - No accessible label
`Contributing
1. Fork the repository
2. Create your feature branch (
git checkout -b feature/amazing-feature)
3. Commit your changes (git commit -m 'Add some amazing feature')
4. Push to the branch (git push origin feature/amazing-feature`)MIT License - see the LICENSE file for details.
For questions and support, please open an issue on GitHub.