kor-ui
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 |
| DescriptionList | Key-value pairs displayed in rows with term and details | default | Layout Components |
| Item | Flexible content row with media, title, description, actions | default, outline, muted | Layout Components |
| Separator | Visual divider between content | horizontal, vertical | Layout Components |
| Portal | Render components outside hierarchy | - | Layout Components |
| List | Performance-optimized list rendering | - | Layout Components |
| Table | Data table with header, body, rows, and cells | default | Layout Components |
| Sidebar | Collapsible navigation sidebar with menu items | default | Layout Components |
Form Inputs
| Component | Description | Variants | Reference |
|---|---|---|---|
| Input | Text input field | default | Input Components |
| NumericInput | Formatted numeric input (currency, percentage, etc.) | default | Input Components |
| PhoneInput | Phone number input with country selector (E.164) | default | Input Components |
| Textarea | Multi-line text input | default | Input Components |
| Checkbox | Toggle selection with label | default, outlined | Input Components |
| RadioGroup | Single selection from a group of options | default, outlined | Input Components |
| Select | Dropdown selection from a list of options | default | Input Components |
| Combobox | Generic autocomplete input with built-in filtering and item selection | default | Input Components |
| Field | Form field wrapper with label and validation | - | Input Components |
Display Components
| Component | Description | Variants | Reference |
|---|---|---|---|
| Typography | Text with semantic variants | heading, body (+ size: sm, md, lg) | Display Components |
| Avatar | User avatar with image and fallback | default | Display Components |
| Badge | Status indicators and labels | default, secondary, success, warning, danger, info | Display Components |
| Icon | Icon rendering with render prop pattern | - | Display Components |
| Empty | Empty state placeholders | default | Display Components |
| Progress | Linear progress indicators | default | Display Components |
Interactive Components
| Component | Description | Variants | Reference |
|---|---|---|---|
| Button | Action buttons with loading states | default, secondary, ghost | Interactive Components |
| IconButton | Icon-only pressable button | default, secondary, ghost | Interactive Components |
| Tabs | Tabbed navigation | default, line | Interactive Components |
| Menu | Dropdown menus | default | Interactive Components |
| Popover | Positioned overlay content | default | Interactive Components |
| Calendar | Month date picker (compound) | default | Interactive Components |
| WeekCalendar | Swipeable week strip with date selection | default | Interactive Components |
| CalendarTimeline | Day timeline with generic event rendering | default | Interactive Components |
Feedback Components
| Component | Description | Variants | Reference |
|---|---|---|---|
| Alert | Inline notifications with icons | default, destructive | Feedback Components |
| AlertDialog | Modal confirmation dialogs | default | Feedback Components |
| Toast | Transient notifications | default, success, danger | Feedback Components |
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="you@example.com" />
<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.
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="you@example.com" />
<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.
Reference Documentation
Consult these detailed references as needed:
Component References
- Layout Components - Card, DescriptionList, Item, Separator, Portal, List, Table
- Input Components - Input, NumericInput, Textarea, Checkbox, RadioGroup, Select, Combobox, Field
- Display Components - Typography, Avatar, Badge, Icon, Empty, Progress
- Interactive Components - Button, Tabs, Menu, Popover, Calendar
- Feedback Components - Alert, AlertDialog, Toast
System References
- Theme Customization - Complete theming guide with color schemes, typography, and responsive design
- Patterns & Recipes - Common implementation patterns for forms, modals, navigation, and feedback
- Troubleshooting - Solutions for setup, component, type, and platform-specific issues
More from korsoftwaresolutions/ui
building-native-ui
Complete guide for building beautiful apps with Expo Router. Covers fundamentals, styling, components, navigation, animations, patterns, and native tabs.
10frontend-design
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, artifacts, posters, or applications (examples include websites, landing pages, dashboards, React components, HTML/CSS layouts, or when styling/beautifying any web UI). Generates creative, polished code and UI design that avoids generic AI aesthetics.
9skill-creator
Create new skills, modify and improve existing skills, and measure skill performance. Use when users want to create a skill from scratch, edit, or optimize an existing skill, run evals to test a skill, benchmark skill performance with variance analysis, or optimize a skill's description for better triggering accuracy.
9marketing-ideas
When the user needs marketing ideas, inspiration, or strategies for their SaaS or software product. Also use when the user asks for 'marketing ideas,' 'growth ideas,' 'how to market,' 'marketing strategies,' 'marketing tactics,' 'ways to promote,' or 'ideas to grow.' This skill provides 139 proven marketing approaches organized by category.
5paid-ads
When the user wants help with paid advertising campaigns on Google Ads, Meta (Facebook/Instagram), LinkedIn, Twitter/X, or other ad platforms. Also use when the user mentions 'PPC,' 'paid media,' 'ad copy,' 'ad creative,' 'ROAS,' 'CPA,' 'ad campaign,' 'retargeting,' or 'audience targeting.' This skill covers campaign strategy, ad creation, audience targeting, and optimization.
4launch-strategy
When the user wants to plan a product launch, feature announcement, or release strategy. Also use when the user mentions 'launch,' 'Product Hunt,' 'feature release,' 'announcement,' 'go-to-market,' 'beta launch,' 'early access,' 'waitlist,' or 'product update.' This skill covers phased launches, channel strategy, and ongoing launch momentum.
4