LOKE Design System

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-system

For 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


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

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