@legalaidalberta/luic
v0.2.0
Published
Legal Aid Alberta's React component library. Built with React, Tailwind CSS v4, react-select, and Zod validation.
Readme
@luic/ui
Legal Aid Alberta's React component library. Built with React, Tailwind CSS v4, react-select, and Zod validation.
Installation
pnpm add @luic/uiQuick Start
import { TextInput, createTextInputSchema } from '@luic/ui';
import '@luic/ui/dist/styles.css';
const schema = createTextInputSchema({ required: true, minLength: 2 });
function MyForm() {
const [name, setName] = useState('');
const [error, setError] = useState<string>();
const handleBlur = () => {
const result = schema.safeParse(name);
setError(result.success ? undefined : result.error.issues[0].message);
};
return (
<TextInput
label="Full Name"
value={name}
onChange={(e) => setName(e.target.value)}
onBlur={handleBlur}
error={error}
required
/>
);
}Components
Selection Controls
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | Select | Single-selection dropdown (react-select) | Choosing one option from a list of 5+; searchable, clearable by default | Binary choices (Toggle), 2-4 visible options (Radio) | | MultiSelect | Multi-selection dropdown (react-select) | Choosing multiple options from a list; tags, filters, categories | Single selection (Select), boolean agreement (Checkbox) | | TagInput | Creatable multi-select for free-text tags | Tags, keywords, labels where users can create new values | Selecting from fixed options only (MultiSelect) | | SearchInput | Text search or async typeahead | Simple search fields (simple mode) or server-side search (async mode) | Selecting from a static list (Select) |
Text Inputs
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | TextInput | Single-line text entry with optional addons | Names, emails, short text, any single-line field | Multi-line text (Textarea), passwords (PasswordInput), URLs (URLInput) | | PasswordInput | Password entry with toggle and strength meter | Password fields, PIN entry, secret keys | General text (TextInput), search (SearchInput) | | Textarea | Multi-line text with character counter | Comments, descriptions, messages | Single-line input (TextInput), rich text editing | | URLInput | URL entry with format validation | Website URLs, API endpoints, link fields | General text (TextInput), email addresses |
Numeric Inputs
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | NumericInput | Number entry with +/- buttons and clamping | Quantities, ages, counts, integers or decimals | Currency (CurrencyInput), percentages (PercentageInput), visual ranges (Slider) | | CurrencyInput | Money entry with currency symbol | Prices, payments, budgets, monetary values | Plain numbers (NumericInput), percentages (PercentageInput) | | PercentageInput | Percentage entry (0-100) with % symbol | Discount rates, completion %, probability | Plain numbers (NumericInput), visual ranges (Slider) | | Slider | Range slider for visual value selection | Volume, brightness, approximate values | Precise number entry (NumericInput), percentage fields (PercentageInput) |
Date & Time
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | DatePicker | Date selection via native input | Birthdates, deadlines, scheduling | Time selection (TimePicker) | | TimePicker | Time selection via native input | Appointment times, schedules | Date selection (DatePicker), durations (NumericInput) |
Boolean & Choice Controls
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | Toggle | On/off switch | Feature flags, settings, boolean preferences | Agreement checkboxes (Checkbox), multi-state options (Select) | | Checkbox | Single checkbox with label | Terms agreement, opt-in/out, boolean fields | On/off switches (Toggle), single selection (Radio) | | Radio | Radio button for group single-selection | 2-5 visible choices: gender, plan selection | Large lists (Select), multiple selections (MultiSelect), on/off (Toggle) |
Specialty Inputs
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | ColorPicker | Color input with hex display and preview | Theme customization, brand colors, design settings | Selecting from predefined options (Select) | | Rating | Star-based rating (1-5) | Reviews, feedback, satisfaction scores | Numeric scores (NumericInput), likes (Toggle) | | FileUpload | File upload with drag-and-drop | Documents, images, attachments | URL links to files (URLInput) |
Data Display
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | DataTable | Simple table with selection and pagination | Data lists, admin tables, simple tabular data | Complex filtering/grouping (AdvancedDataGrid) | | AdvancedDataGrid | Feature-rich grid with filtering, sorting, grouping, search, export, inline editing | Complex data management, admin dashboards, reporting | Simple lists (DataTable), fewer than 10 items |
Layout
| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | Card | Container for grouping content | Dashboard widgets, content sections, summary panels | Form layouts (FormField), data display (DataTable) |
Shared Props
All form components support these base props:
| Prop | Type | Description |
|------|------|-------------|
| label | string | Field label |
| error | string | Error message |
| errors | string[] | Multiple validation errors (from Zod) |
| helperText | string | Helper/hint text below the field |
| disabled | boolean | Disables the field |
| required | boolean | Marks the field as required |
| size | 'sm' \| 'md' \| 'lg' | Size variant (default: 'md') |
| colorVariant | 'default' \| 'primary' \| 'success' \| 'error' \| 'warning' | Color accent |
Zod Validation
Every component has a co-located Zod schema. Import directly from the component or from the validation barrel:
// From component
import { createTextInputSchema } from '@luic/ui';
// All schemas available
import {
createTextInputSchema,
createPasswordSchema,
createTextareaSchema,
urlSchema,
createNumericInputSchema,
currencySchema,
percentageSchema,
createDateSchema,
timeSchema,
colorSchema,
ratingSchema,
createSelectSchema,
createMultiSelectSchema,
createTagsSchema,
createSearchInputSchema,
fileSchema,
toggleSchema,
checkboxSchema,
radioSchema,
} from '@luic/ui';useFormValidation Hook
Framework-agnostic validation hook that works with any form library:
import { useFormValidation, createTextInputSchema } from '@luic/ui';
function MyInput() {
const [value, setValue] = useState('');
const { errors, getValidationProps } = useFormValidation({
schema: createTextInputSchema({ required: true, minLength: 3 }),
mode: 'onBlur', // 'onBlur' | 'onChange' | 'onSubmit'
});
return (
<TextInput
label="Name"
value={value}
onChange={(e) => setValue(e.target.value)}
errors={errors}
{...getValidationProps(value)}
/>
);
}React Select Customization
For advanced react-select customization, the theme layer is exported:
import { LuicSelectBase, getLuicSelectStyles } from '@luic/ui';
// Use LuicSelectBase directly for custom select implementations
// Use getLuicSelectStyles() to get the Luic theme for your own react-select instancesDevelopment
pnpm install # Install dependencies
pnpm dev # Start Vite dev server
pnpm storybook # Start Storybook
pnpm build # Build (ES + CJS + UMD + types + CSS)
pnpm test # Run tests (Vitest + Playwright)
pnpm lint # Run ESLintBuild Output
dist/
luic.es.js # ES module
luic.cjs.js # CommonJS
luic.umd.js # UMD (global: LuicUI)
styles.css # Tailwind CSS
index.d.ts # TypeScript declarations