Skip to main content

Getting Started

This guide covers common usage patterns for the Openlane UI component library. All examples use real components from the @repo/ui package.

Basic Components

Button Component

The Button component supports multiple variants, sizes, icons, and loading states:
import { Button } from '@repo/ui/button'

export function Example() {
  return (
    <div className="flex gap-2">
      <Button variant="primary">Primary Button</Button>
      <Button variant="secondary">Secondary Button</Button>
      <Button variant="destructive">Delete</Button>
    </div>
  )
}

Input Component

The Input component supports prefixes, suffixes, and icons:
import { Input } from '@repo/ui/input'

export function Example() {
  return (
    <Input 
      type="text" 
      placeholder="Enter your email"
      maxWidth
    />
  )
}

Alert Component

Compose alerts with title and description:
import { Alert, AlertTitle, AlertDescription } from '@repo/ui/alert'

export function Example() {
  return (
    <div className="space-y-4">
      <Alert variant="default">
        <AlertTitle>Heads up!</AlertTitle>
        <AlertDescription>
          You can add components to your app using the CLI.
        </AlertDescription>
      </Alert>
      
      <Alert variant="destructive">
        <AlertTitle>Error</AlertTitle>
        <AlertDescription>
          Your session has expired. Please log in again.
        </AlertDescription>
      </Alert>
    </div>
  )
}

Badge Component

Display status indicators and labels:
import { Badge } from '@repo/ui/badge'

export function Example() {
  return (
    <div className="flex gap-2">
      <Badge variant="default">Default</Badge>
      <Badge variant="secondary">Secondary</Badge>
      <Badge variant="green">Active</Badge>
      <Badge variant="blue">Info</Badge>
      <Badge variant="destructive">Error</Badge>
      <Badge variant="gold">Premium</Badge>
    </div>
  )
}

Form Components

React Hook Form Integration

The library provides seamless integration with React Hook Form:
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import * as z from 'zod'
import {
  Form,
  FormField,
  FormItem,
  FormLabel,
  FormControl,
  FormDescription,
  FormMessage,
} from '@repo/ui/form'
import { Input } from '@repo/ui/input'
import { Button } from '@repo/ui/button'

const formSchema = z.object({
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
})

export function LoginForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      email: '',
      password: '',
    },
  })
  
  const onSubmit = (data: z.infer<typeof formSchema>) => {
    console.log(data)
  }
  
  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input placeholder="[email protected]" {...field} />
              </FormControl>
              <FormDescription>
                We'll never share your email.
              </FormDescription>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input type="password" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        
        <Button type="submit" variant="primary">Sign In</Button>
      </form>
    </Form>
  )
}

Layout Components

Tabs Component

Organize content with tabs:
import { Tabs } from '@repo/ui/tabs'

export function Example() {
  return (
    <Tabs defaultValue="account" className="w-full">
      <Tabs.List>
        <Tabs.Trigger value="account">Account</Tabs.Trigger>
        <Tabs.Trigger value="password">Password</Tabs.Trigger>
        <Tabs.Trigger value="settings">Settings</Tabs.Trigger>
      </Tabs.List>
      
      <Tabs.Content value="account">
        <p>Manage your account settings here.</p>
      </Tabs.Content>
      
      <Tabs.Content value="password">
        <p>Change your password here.</p>
      </Tabs.Content>
      
      <Tabs.Content value="settings">
        <p>Update your preferences here.</p>
      </Tabs.Content>
    </Tabs>
  )
}

Dialog Component

Create modal dialogs:
import { Dialog } from '@repo/ui/dialog'
import { Button } from '@repo/ui/button'
import { useState } from 'react'

export function Example() {
  const [open, setOpen] = useState(false)
  
  return (
    <>
      <Button onClick={() => setOpen(true)}>Open Dialog</Button>
      
      <Dialog open={open} onOpenChange={setOpen}>
        <Dialog.Content>
          <Dialog.Header>
            <Dialog.Title>Confirm Action</Dialog.Title>
            <Dialog.Description>
              Are you sure you want to continue?
            </Dialog.Description>
          </Dialog.Header>
          
          <div className="py-4">
            <p>This action cannot be undone.</p>
          </div>
          
          <Dialog.Footer>
            <Button variant="secondary" onClick={() => setOpen(false)}>
              Cancel
            </Button>
            <Button variant="primary" onClick={() => setOpen(false)}>
              Confirm
            </Button>
          </Dialog.Footer>
        </Dialog.Content>
      </Dialog>
    </>
  )
}

Data Display Components

Data Table

Build powerful data tables with TanStack Table:
import { DataTable } from '@repo/ui/data-table'
import { useState } from 'react'

interface User {
  id: string
  name: string
  email: string
  role: string
}

const columns = [
  {
    accessorKey: 'name',
    header: 'Name',
  },
  {
    accessorKey: 'email',
    header: 'Email',
  },
  {
    accessorKey: 'role',
    header: 'Role',
  },
]

export function Example() {
  const [data] = useState<User[]>([
    { id: '1', name: 'John Doe', email: '[email protected]', role: 'Admin' },
    { id: '2', name: 'Jane Smith', email: '[email protected]', role: 'User' },
  ])
  
  return (
    <DataTable
      columns={columns}
      data={data}
    />
  )
}

Feedback Components

Toast Notifications

Show toast notifications using Sonner:
import { Toaster } from '@repo/ui/toaster'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Toaster />
      </body>
    </html>
  )
}

Tooltip

Add tooltips to provide additional context:
import { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider } from '@repo/ui/tooltip'
import { Button } from '@repo/ui/button'

export function Example() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger asChild>
          <Button variant="iconButton">?</Button>
        </TooltipTrigger>
        <TooltipContent>
          <p>This is helpful information</p>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  )
}

Utility Functions

cn() - Class Name Utility

Merge Tailwind classes intelligently:
import { cn } from '@repo/ui/lib/utils'

export function Example({ className, isActive }) {
  return (
    <div
      className={cn(
        'px-4 py-2 rounded-md',
        isActive && 'bg-primary text-primary-foreground',
        className
      )}
    >
      Content
    </div>
  )
}

Best Practices

Use individual imports to enable tree-shaking:
// Good - Tree-shakeable
import { Button } from '@repo/ui/button'
import { Input } from '@repo/ui/input'

// Avoid - Not tree-shakeable
import { Button, Input } from '@repo/ui'
Take advantage of built-in TypeScript types:
import { Button, type ButtonProps } from '@repo/ui/button'

interface MyButtonProps extends ButtonProps {
  customProp?: string
}
Use component composition for flexibility:
// Good - Flexible composition
<Alert>
  <AlertTitle>Title</AlertTitle>
  <AlertDescription>Description</AlertDescription>
</Alert>

// Avoid - Less flexible
<Alert title="Title" description="Description" />
Add custom styling with Tailwind classes:
<Button 
  variant="primary"
  className="w-full md:w-auto shadow-lg"
>
  Click me
</Button>

Next Steps

Theming

Customize colors and design tokens

Storybook

Explore all components interactively

Component Overview

View all available components

Installation

Review installation steps

Build docs developers (and LLMs) love