Contributing
Contributing to the LOKE Design System — concepts, setup, usage patterns, and writing documentation.
Contributing
This page covers deeper technical details about the LOKE Design System for contributors — including architecture concepts, theming, common patterns, and how to write documentation.
Looking to get started using the design system? See the Quick Start guide instead. This page is for contributors who need deeper context.
Key concepts
- Individual imports
- Import only what you use to keep bundles small
- TypeScript‑first
- Rich types across components and utilities
- Tailwind‑based styling
- Class‑driven, utility‑first styling
- Accessibility baked in
- Sensible ARIA usage, keyboard navigation, visible focus
- Dark mode
- Fully themed, light and dark compatible
Installation
Install the package in your app:
# bun (recommended)
bun add @loke/design-system
# npm
npm install @loke/design-systemFor a step-by-step walkthrough including TypeScript configuration, see the Quick Start Guide.
Project setup
Ensure your tsconfig.json uses bundler module resolution:
{
"compilerOptions": {
"module": "esnext",
"moduleResolution": "bundler"
}
}Add the design system styles in your root (e.g. Next.js app layout or entry file):
// app/layout.tsx or main entry
import '@loke/design-system/styles';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}That’s it — the system includes its CSS variables and Tailwind integration. You can begin importing components individually.
Usage guidelines
Import only what you need
// Good: individual imports
import { Button } from '@loke/design-system/button';
import { Card, CardHeader, CardTitle, CardContent } from '@loke/design-system/card';// Example component usage (MDX or app code)
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
</CardHeader>
<CardContent>
<p>Card content</p>
<Button>Action</Button>
</CardContent>
</Card>Tips:
- Prefer individual imports: import { Button } from '@loke/design-system/button'
- Compose primitives (e.g. Box, Stack, Columns) for consistent spacing and layout
- Keep accessibility in mind (labels, alt text, keyboard flows)
Layout primitives
The system includes primitives to build consistent layouts:
import { Box } from '@loke/design-system/box';
import { Stack } from '@loke/design-system/stack';
import { Columns, Column } from '@loke/design-system/columns';
function MyLayout() {
return (
<Box padding={4}>
<Stack gap={6}>
<h1>Page Title</h1>
<Columns columns={[1, 2, 3]} gap={4}>
<Box padding={4} background="card" borderRadius="md">Column 1</Box>
<Box padding={4} background="card" borderRadius="md">Column 2</Box>
<Box padding={4} background="card" borderRadius="md">Column 3</Box>
</Columns>
</Stack>
</Box>
);
}Icons
Use the included icon set for a consistent look:
import { Search, ArrowRight } from '@loke/icons';
<Button>
Next <ArrowRight className="ml-2 h-4 w-4" />
</Button>Theming and colors
Semantic tokens
The system ships a semantic color palette via CSS variables:
- --primary / --primary-foreground
- --secondary / --secondary-foreground
- --background / --foreground
- --card / --card-foreground
- --muted / --muted-foreground
- --accent / --accent-foreground
- --destructive / --destructive-foreground
- --border, --input, --ring
Use them via Tailwind tokens or directly with CSS vars:
<div className="bg-card text-card-foreground p-4 rounded-lg">
Card Content
</div>.my-element {
background: var(--accent);
color: var(--accent-foreground);
}See the interactive palette and guidelines:
- Color System: /docs/brand/colors
Dark mode
Enable dark mode by toggling the dark class on the root:
function ThemeToggle() {
const [isDark, setIsDark] = React.useState(false);
React.useEffect(() => {
document.documentElement.classList.toggle('dark', isDark);
}, [isDark]);
return (
<button onClick={() => setIsDark(!isDark)}>
Toggle {isDark ? 'Light' : 'Dark'} Mode
</button>
);
}Common patterns
Forms
import { Form, FormField, FormItem, FormLabel, FormControl } from '@loke/design-system/form';
import { Input } from '@loke/design-system/input';
import { Button } from '@loke/design-system/button';
function LoginForm() {
// Assume form setup with your favorite form library
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="email@loke.com" {...field} />
</FormControl>
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
</FormItem>
)}
/>
<Button type="submit">Login</Button>
</form>
</Form>
);
}Data display
import {
Table,
TableHeader,
TableBody,
TableRow,
TableHead,
TableCell,
} from '@loke/design-system/table';
import { Badge } from '@loke/design-system/badge';
function DataTable({ data }: { data: { id: string; name: string; status: 'active' | 'inactive' }[] }) {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>ID</TableHead>
<TableHead>Name</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{data.map((item) => (
<TableRow key={item.id}>
<TableCell>{item.id}</TableCell>
<TableCell>{item.name}</TableCell>
<TableCell>
<Badge variant={item.status === 'active' ? 'default' : 'outline'}>
{item.status}
</Badge>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
);
}Accessibility
- Use semantic HTML and labeled controls
- Ensure sufficient color contrast
- Verify keyboard and screen reader flows
- Prefer component APIs over ad‑hoc markup
Read the full guide:
- Accessibility Guide: /docs/guides/accessibility
Quick links for LOKE developers
- Quick Start — Get up and running fast
- Tailwind CSS Guide — How Tailwind relates to the design system
- Color System — LOKE brand colors and semantic tokens
- Logo Guidelines — Official LOKE logo assets
- Accessibility Guide — Building inclusive experiences
- Component Guide — Comprehensive component reference
- Migrations — Version upgrade guides
Tailwind CSS
The design system is built with Tailwind CSS, but you do not need to install Tailwind to use it. All styles are pre-compiled and included when you import @loke/design-system/styles.
If you're familiar with Tailwind, you can use utility classes alongside design system components — common classes like p-4, flex, gap-4, bg-primary, etc. are included in the pre-compiled stylesheet.
The layout components (Box, Stack, Columns) provide equivalent functionality to common Tailwind layout patterns through a props-based API.
For full details, see the Tailwind CSS Guide.
Troubleshooting
- Styles not loading
- Ensure import '@loke/design-system/styles' is present in your root
- Dark mode not toggling
- Confirm the dark class is being added to html
- Type errors
- Verify you're importing the correct path for a component (individual import paths)
- "Cannot find module" errors
- Set moduleResolution: "bundler" in your
tsconfig.json
- Set moduleResolution: "bundler" in your
Writing documentation with MDX
This site uses custom components to enhance documentation. Here's what's available:
Custom MDX components
You can use the following custom components inside MDX pages to keep content consistent and easy to scan.
Callout
<Callout type="info">
This is an informational callout used to surface important context.
</Callout>
<Callout type="success">
This indicates a successful action or a positive state.
</Callout>
<Callout type="warning">
This warns the reader about potential issues.
</Callout>
<Callout type="error">
This highlights a critical problem or a blocking issue.
</Callout>Kbd
Use <Kbd> for keyboard keys or shortcuts.
Examples:
- Press Cmd + K to open search
- Take a screenshot with Shift + Cmd + 4
- Confirm with Enter and cancel with Esc
Variants:
- Default: Ctrl
- Small: Ctrl
- Outline: Ctrl
- Large: Ctrl
TypeTable
Use TypeTable (from fumadocs-ui) to quickly document API props for a component.
import { TypeTable } from 'fumadocs-ui/components/type-table';
<TypeTable
type={{
variant: {
description: 'Visual style of the button',
type: '"default" | "secondary" | "ghost" | "link" | "destructive"',
default: '"default"',
},
size: {
description: 'Controls the button sizing',
type: '"sm" | "md" | "lg" | "icon"',
default: '"md"',
},
disabled: {
description: 'Disables user interaction',
type: 'boolean',
default: 'false',
},
onClick: {
description: 'Click handler for the button',
type: '(e: React.MouseEvent<HTMLButtonElement>) => void',
},
}}
/>Next steps for contributors
- Contribution Guide — How to add or improve components
- Review the Color System and Logo Guidelines to maintain LOKE brand consistency
- Use layout primitives (Box, Stack, Columns) to establish consistent structure
- Reference the Accessibility Guide while building features to ensure all LOKE products are inclusive
- Check the Component Guide to understand when to use each component