KorUI Library
KorUI (@korsolutions/ui) is a minimal-dependency, cross-platform UI library for React Native and Expo. Flexible components with beautiful default styling, compound component patterns, and comprehensive theming support.
Core Principles
- Beautiful Defaults: Components ship with production-ready styling and a flexible variant system
- Compound Components: All components follow Root + sub-component pattern
- Variant System: Each component offers multiple style variants
- Minimal Dependencies: Only React Native and Expo core dependencies
- Full TypeScript Support: Complete type definitions for all components
- Cross-Platform: iOS, Android, and Web support
Quick Start
Installation
npm install @korsolutions/ui
# or
yarn add @korsolutions/ui
# or
bun add @korsolutions/ui
Provider Setup
Wrap your application with UIProvider in your root layout:
import { UIProvider } from "@korsolutions/ui";
import { useSafeAreaInsets } from "react-native-safe-area-context";
export default function RootLayout() {
const safeAreaInsets = useSafeAreaInsets();
return (
<UIProvider safeAreaInsets={safeAreaInsets}>
<YourApp />
</UIProvider>
);
}
Basic Import Pattern
import { Button, Input, Card } from "@korsolutions/ui";
function MyComponent() {
return (
<Card.Root>
<Card.Body>
<Button onPress={() => console.log("Pressed")}>
Click Me
</Button>
</Card.Body>
</Card.Root>
);
}
Your First Component
import { useState } from "react";
import { Button } from "@korsolutions/ui";
function SubmitButton() {
const [loading, setLoading] = useState(false);
const handleSubmit = async () => {
setLoading(true);
await submitForm();
setLoading(false);
};
return (
<Button variant="default" isLoading={loading} onPress={handleSubmit}>
Submit
</Button>
);
}
Component Overview
Layout & Structure
| Component |
Description |
Variants |
Reference |
| Card |
Content container with header, body, and footer |
default |
[Layout Components](./references/components-layout.md#card) |
| DescriptionList |
Key-value pairs displayed in rows with term and details |
default |
[Layout Components](./references/components-layout.md#descriptionlist) |
| Item |
Flexible content row with media, title, description, actions |
default, outline, muted |
[Layout Components](./references/components-layout.md#item) |
| Separator |
Visual divider between content |
horizontal, vertical |
[Layout Components](./references/components-layout.md#separator) |
| Portal |
Render components outside hierarchy |
- |
[Layout Components](./references/components-layout.md#portal) |
| List |
Performance-optimized list rendering |
- |
[Layout Components](./references/components-layout.md#list) |
| Table |
Data table with header, body, rows, and cells |
default |
[Layout Components](./references/components-layout.md#table) |
| Sidebar |
Collapsible navigation sidebar with menu items |
default |
[Layout Components](./references/components-layout.md#sidebar) |
Form Inputs
| Component |
Description |
Variants |
Reference |
| Input |
Text input field |
default |
[Input Components](./references/components-inputs.md#input) |
| NumericInput |
Formatted numeric input (currency, percentage, etc.) |
default |
[Input Components](./references/components-inputs.md#numericinput) |
| PhoneInput |
Phone number input with country selector (E.164) |
default |
[Input Components](./references/components-inputs.md#phoneinput) |
| Textarea |
Multi-line text input |
default |
[Input Components](./references/components-inputs.md#textarea) |
| Checkbox |
Toggle selection with label |
default, outlined |
[Input Components](./references/components-inputs.md#checkbox) |
| RadioGroup |
Single selection from a group of options |
default, outlined |
[Input Components](./references/components-inputs.md#radiogroup) |
| Select |
Dropdown selection from a list of options |
default |
[Input Components](./references/components-inputs.md#select) |
| Combobox |
Generic autocomplete input with built-in filtering and item selection |
default |
[Input Components](./references/components-inputs.md#combobox) |
| Field |
Form field wrapper with label and validation |
- |
[Input Components](./references/components-inputs.md#field) |
Display Components
| Component |
Description |
Variants |
Reference |
| Typography |
Text with semantic variants |
heading, body (+ size: sm, md, lg) |
[Display Components](./references/components-display.md#typography) |
| Avatar |
User avatar with image and fallback |
default |
[Display Components](./references/components-display.md#avatar) |
| Badge |
Status indicators and labels |
default, secondary, success, warning, danger, info |
[Display Components](./references/components-display.md#badge) |
| Icon |
Icon rendering with render prop pattern |
- |
[Display Components](./references/components-display.md#icon) |
| Empty |
Empty state placeholders |
default |
[Display Components](./references/components-display.md#empty) |
| Progress |
Linear progress indicators |
default |
[Display Components](./references/components-display.md#progress) |
Interactive Components
| Component |
Description |
Variants |
Reference |
| Button |
Action buttons with loading states |
default, secondary, ghost |
[Interactive Components](./references/components-interactive.md#button) |
| IconButton |
Icon-only pressable button |
default, secondary, ghost |
[Interactive Components](./references/components-interactive.md#iconbutton) |
| Tabs |
Tabbed navigation |
default, line |
[Interactive Components](./references/components-interactive.md#tabs) |
| Menu |
Dropdown menus |
default |
[Interactive Components](./references/components-interactive.md#menu) |
| Popover |
Positioned overlay content |
default |
[Interactive Components](./references/components-interactive.md#popover) |
| Calendar |
Month date picker (compound) |
default |
[Interactive Components](./references/components-interactive.md#calendar) |
| WeekCalendar |
Swipeable week strip with date selection |
default |
[Interactive Components](./references/components-interactive.md#weekcalendar) |
| CalendarTimeline |
Day timeline with generic event rendering |
default |
[Interactive Components](./references/components-interactive.md#calendartimeline) |
Feedback Components
| Component |
Description |
Variants |
Reference |
| Alert |
Inline notifications with icons |
default, destructive |
[Feedback Components](./references/components-feedback.md#alert) |
| AlertDialog |
Modal confirmation dialogs |
default |
[Feedback Components](./references/components-feedback.md#alertdialog) |
| Toast |
Transient notifications |
default, success, danger |
[Feedback Components](./references/components-feedback.md#toast) |
Compound Component Pattern
All KorUI components follow a compound component pattern where a parent component (usually Root) provides context to child sub-components.
Structure
<Component.Root {...rootProps}>
<Component.SubComponent1 {...props} />
<Component.SubComponent2 {...props} />
</Component.Root>
Common Sub-Components
Most components share similar sub-component naming:
- Root - Parent container that provides context
- Label - Text label for the component
- Icon - Icon display with render prop pattern
- Description - Secondary descriptive text
- Title - Primary heading text
- Body - Main content area
- Header - Top section
- Footer - Bottom section
Example: Button
<Button variant="default" onPress={handlePress} isLoading={loading}>
Submit Form
</Button>
Example: Alert with Icon
import { AlertCircle } from "lucide-react-native";
<Alert.Root variant="destructive">
<Alert.Icon render={AlertCircle} />
<Alert.Body>
<Alert.Title>Error</Alert.Title>
<Alert.Description>Something went wrong</Alert.Description>
</Alert.Body>
</Alert.Root>;
Example: Field with Input
<Field.Root>
<Field.Label for="email">Email Address</Field.Label>
<Input id="email" value={email} onChange={setEmail} placeholder="[email protected]" />
<Field.Description>We'll never share your email.</Field.Description>
{error && <Field.Error>{error}</Field.Error>}
</Field.Root>
Style Composition
Component styles are always composed with variant styles first, allowing user styles to override:
// Variant styles are applied first
<Button style={{ marginTop: 16 }}>
Custom Button
</Button>
This ensures your custom styles always take precedence over variant defaults.
Theme System Basics
KorUI includes a comprehensive theming system with light/dark mode support.
Theme Tokens
The theme provides these customizable tokens:
- colors - Color palette with light/dark schemes
- radius - Border radius (default: 10)
- fontSize - Base font size (default: 16)
- fontFamily - Font family (default: "System")
- letterSpacing - Letter spacing (default: 0)
Color Tokens
Each color scheme (light/dark) includes:
- background - Main background color
- foreground - Main text color
- primary - Primary brand color
- primaryForeground - Text on primary color
- secondary - Secondary brand color
- secondaryForeground - Text on secondary color
- muted - Muted background color
- mutedForeground - Muted text color
- border - Border color
- surface - Surface/card background
- success, warning, danger, info - Semantic colors
Using the Theme
Access the theme in your components:
import { useTheme } from "@korsolutions/ui";
function MyComponent() {
const theme = useTheme();
return (
<View
style={{
backgroundColor: theme.colors.background,
borderRadius: theme.radius,
padding: 16,
}}
>
<Text
style={{
color: theme.colors.foreground,
fontSize: theme.fontSize,
fontFamily: theme.fontFamily,
}}
>
Themed Content
</Text>
</View>
);
}
Color Scheme
Toggle between light and dark mode:
const theme = useTheme();
// Get current scheme
console.log(theme.colorScheme); // "light" | "dark"
// Set color scheme
theme.setColorScheme("dark");
Quick Customization
Customize the theme via UIProvider:
<UIProvider
theme={{
radius: 12,
fontSize: 18,
colors: {
light: {
primary: "hsla(220, 90%, 56%, 1)",
primaryForeground: "hsla(0, 0%, 100%, 1)",
},
dark: {
primary: "hsla(220, 90%, 70%, 1)",
primaryForeground: "hsla(0, 0%, 100%, 1)",
},
},
}}
safeAreaInsets={safeAreaInsets}
>
<App />
</UIProvider>
For detailed theming documentation, see [Theme Customization](./references/theme-customization.md).
Common Patterns
Form Field with Validation
import { Field, Input } from "@korsolutions/ui";
<Field.Root>
<Field.Label for="email">Email</Field.Label>
<Input id="email" value={email} onChange={setEmail} placeholder="[email protected]" />
<Field.Description>Enter your email address</Field.Description>
{error && <Field.Error>{error}</Field.Error>}
</Field.Root>;
Icons with Render Prop
KorUI uses a render prop pattern for icons, supporting any icon library:
import { AlertCircle, CheckCircle } from "lucide-react-native";
import { Alert } from "@korsolutions/ui";
// With lucide-react-native
<Alert.Icon render={AlertCircle} />
// With custom function
<Alert.Icon render={(props) => <CheckCircle {...props} size={20} />} />
// With lucide-react-native
import { AlertCircle } from "lucide-react-native";
<Alert.Icon render={AlertCircle} />
Icon Button
A pressable button that renders a single icon. Uses the same render prop pattern as Icon:
import { IconButton } from "@korsolutions/ui";
import { Heart, Settings, Trash } from "lucide-react-native";
// Basic usage
<IconButton render={Heart} onPress={() => console.log("Liked")} />
// Variants (matches Button variants)
<IconButton render={Settings} variant="secondary" />
<IconButton render={Settings} variant="ghost" />
// Custom size and color
<IconButton render={Trash} size={32} color="red" />
// Disabled
<IconButton render={Heart} isDisabled />
Separator
A visual divider between content sections:
import { Separator } from "@korsolutions/ui";
// Horizontal (default)
<Separator />
// Vertical
<Separator variant="vertical" />
Controlled State Management
Most input components use controlled state:
import { useState } from "react";
import { Input, Checkbox } from "@korsolutions/ui";
function Form() {
const [text, setText] = useState("");
const [checked, setChecked] = useState(false);
return (
<>
<Input value={text} onChange={setText} />
<Checkbox.Root checked={checked} onChange={setChecked}>
<Checkbox.Indicator />
<Checkbox.Content>
<Checkbox.Title>Accept terms</Checkbox.Title>
</Checkbox.Content>
</Checkbox.Root>
</>
);
}
Loading States
Buttons support loading states with built-in spinner:
<Button isLoading={isSubmitting} onPress={handleSubmit}>
Submit
</Button>
When isLoading is true, the button displays ActivityIndicator and disables interaction.
Disabled States
Most components support disabled states:
<Button isDisabled={!formValid} onPress={handleSubmit}>
Submit
</Button>
<Input isDisabled value={email} onChange={setEmail} />
<Checkbox.Root disabled checked={value} onChange={setValue}>
<Checkbox.Indicator />
<Checkbox.Content>
<Checkbox.Title>Disabled option</Checkbox.Title>
</Checkbox.Content>
</Checkbox.Root>
Selecting Variants
Most components offer multiple variants:
// Button variants
<Button variant="default">
Default Button
</Button>
<Button variant="secondary">
Secondary Button
</Button>
<Button variant="ghost">
Ghost Button
</Button>
// Alert variants
<Alert.Root variant="default">
<Alert.Body>
<Alert.Title>Info</Alert.Title>
</Alert.Body>
</Alert.Root>
<Alert.Root variant="destructive">
<Alert.Body>
<Alert.Title>Error</Alert.Title>
</Alert.Body>
</Alert.Root>
// Badge variants
<Badge variant="success">Active</Badge>
<Badge variant="danger">Inactive</Badge>
<Badge variant="warning">Pending</Badge>
Style Overrides
Override component styles using the style prop:
<Button
style={{
marginTop: 20,
backgroundColor: "blue",
}}
>
Custom Styled
</Button>
Import Reference
Component Imports
// Import individual components
import { Button, Input, Card, Alert } from "@korsolutions/ui";
// Import all components
import * as UI from "@korsolutions/ui";
Hook Imports
// Theme hook
import { useTheme } from "@korsolutions/ui";
// Responsive design hook
import { useScreenSize } from "@korsolutions/ui";
// React Navigation theme integration
import { useReactNavigationTheme } from "@korsolutions/ui";
Provider Import
import { UIProvider } from "@korsolutions/ui";
Type Imports
// Component prop types
import type { ButtonProps } from "@korsolutions/ui";
import type { InputProps } from "@korsolutions/ui";
// Theme types
import type { ThemeAssets, Colors } from "@korsolutions/ui";
Quick Troubleshooting
Provider Not Wrapping App
Issue: Components don't render or theme doesn't apply
Solution: Ensure UIProvider wraps your app in the root layout:
// app/_layout.tsx
import { UIProvider } from "@korsolutions/ui";
export default function RootLayout() {
return (
<UIProvider>
<Stack />
</UIProvider>
);
}
Import Errors
Issue: Cannot resolve @korsolutions/ui
Solution: Install the package and restart your bundler:
npm install @korsolutions/ui
# Restart Metro bundler
Theme Not Updating
Issue: Theme changes don't reflect in components
Solution: Ensure theme customization is passed to UIProvider before app renders:
const customTheme = {
colors: { light: { primary: "hsla(220, 90%, 56%, 1)" } },
};
<UIProvider theme={customTheme}>
<App />
</UIProvider>;
Styles Not Applying
Issue: Custom styles don't override component styles
Solution: Remember style composition order - user styles always override variant styles:
// This works - style prop overrides variant
<Button style={{ backgroundColor: "red" }}>
Red Button
</Button>
For comprehensive troubleshooting, see [Troubleshooting Guide](./references/troubleshooting.md).
Reference Documentation
Consult these detailed references as needed:
Component References
- [Layout Components](./references/components-layout.md) - Card, DescriptionList, Item, Separator, Portal, List, Table
- [Input Components](./references/components-inputs.md) - Input, NumericInput, Textarea, Checkbox, RadioGroup, Select, Combobox, Field
- [Display Components](./references/components-display.md) - Typography, Avatar, Badge, Icon, Empty, Progress
- [Interactive Components](./references/components-interactive.md) - Button, Tabs, Menu, Popover, Calendar
- [Feedback Components](./references/components-feedback.md) - Alert, AlertDialog, Toast
System References
- [Theme Customization](./references/theme-customization.md) - Complete theming guide with color schemes, typography, and responsive design
- [Patterns & Recipes](./references/patterns-recipes.md) - Common implementation patterns for forms, modals, navigation, and feedback
- [Troubleshooting](./references/troubleshooting.md) - Solutions for setup, component, type, and platform-specific issues