> ## Documentation Index
> Fetch the complete documentation index at: https://zarna.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Component Patterns

> Architecture patterns and best practices for React components

## Component Architecture

Zarna components follow consistent patterns based on shadcn/ui conventions and React best practices.

## Basic Component Structure

### shadcn/ui Pattern

All shadcn components follow this structure:

```typescript theme={null}
// components/ui/button.tsx
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"

// 1. Define variants with CVA
const buttonVariants = cva(
  // Base classes applied to all variants
  "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default: "bg-primary text-primary-foreground hover:bg-primary/90",
        destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
        outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
        secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
        ghost: "hover:bg-accent hover:text-accent-foreground",
        link: "text-primary underline-offset-4 hover:underline"
      },
      size: {
        default: "h-10 px-4 py-2",
        sm: "h-9 rounded-md px-3",
        lg: "h-11 rounded-md px-8",
        icon: "h-10 w-10"
      }
    },
    defaultVariants: {
      variant: "default",
      size: "default"
    }
  }
)

// 2. Define props interface
export interface ButtonProps
  extends React.ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  asChild?: boolean
}

// 3. Export component with variants
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, variant, size, asChild = false, ...props }, ref) => {
    const Comp = asChild ? Slot : "button"
    return (
      <Comp
        className={cn(buttonVariants({ variant, size, className }))}
        ref={ref}
        {...props}
      />
    )
  }
)
Button.displayName = "Button"

export { Button, buttonVariants }
```

## Component Patterns

### 1. Composable Components

Break components into smaller, reusable pieces:

```tsx theme={null}
// ✅ Good - Composable
<Card>
  <CardHeader>
    <CardTitle>Company Details</CardTitle>
    <CardDescription>View and edit company information</CardDescription>
  </CardHeader>
  <CardContent>
    <CompanyForm />
  </CardContent>
  <CardFooter>
    <Button>Save Changes</Button>
  </CardFooter>
</Card>

// ❌ Bad - Monolithic
<CompanyCard
  title="Company Details"
  description="View and edit..."
  content={<CompanyForm />}
  footer={<Button>Save</Button>}
/>
```

### 2. Polymorphic Components

Use `asChild` for component flexibility:

```tsx theme={null}
import { Button } from "@/components/ui/button"
import Link from "react-router-dom"

// Render as link
<Button asChild>
  <Link to="/dashboard">Go to Dashboard</Link>
</Button>

// Render as button (default)
<Button onClick={handleClick}>Click Me</Button>
```

### 3. Forwarding Refs

Always forward refs for flexibility:

```tsx theme={null}
const MyComponent = React.forwardRef<HTMLDivElement, MyComponentProps>(
  (props, ref) => {
    return <div ref={ref} {...props} />
  }
)
MyComponent.displayName = "MyComponent"
```

### 4. Controlled vs Uncontrolled

**Controlled** (recommended for forms):

```tsx theme={null}
function SearchInput() {
  const [value, setValue] = useState("")

  return (
    <Input
      value={value}
      onChange={(e) => setValue(e.target.value)}
    />
  )
}
```

**Uncontrolled** (for simple cases):

```tsx theme={null}
function SearchInput() {
  const inputRef = useRef<HTMLInputElement>(null)

  const handleSubmit = () => {
    console.log(inputRef.current?.value)
  }

  return <Input ref={inputRef} />
}
```

## Creating Custom Components

### Example: Custom Card Component

```typescript theme={null}
"use client" // Only if using hooks or browser APIs

import * as React from "react"
import { cn } from "@/lib/utils"
import { cva, type VariantProps } from "class-variance-authority"
import { Badge } from "@/components/ui/badge"

const companyCardVariants = cva(
  "rounded-lg border bg-card text-card-foreground shadow-sm transition-all hover:shadow-md",
  {
    variants: {
      status: {
        active: "border-green-500",
        inactive: "border-gray-300",
        archived: "border-red-500 opacity-75"
      }
    },
    defaultVariants: {
      status: "active"
    }
  }
)

interface CompanyCardProps
  extends React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof companyCardVariants> {
  company: {
    id: string
    name: string
    industry?: string
    revenue?: number
    status: "active" | "inactive" | "archived"
  }
}

export function CompanyCard({
  company,
  status,
  className,
  ...props
}: CompanyCardProps) {
  return (
    <div
      className={cn(companyCardVariants({ status }), className)}
      {...props}
    >
      <div className="p-6">
        <div className="flex items-start justify-between">
          <div>
            <h3 className="text-lg font-semibold">{company.name}</h3>
            {company.industry && (
              <p className="text-sm text-muted-foreground mt-1">
                {company.industry}
              </p>
            )}
          </div>
          <Badge variant={company.status === "active" ? "default" : "secondary"}>
            {company.status}
          </Badge>
        </div>

        {company.revenue && (
          <p className="mt-4 text-2xl font-bold">
            ${(company.revenue / 1000000).toFixed(1)}M
          </p>
        )}
      </div>
    </div>
  )
}
```

## Common Component Patterns

### Loading States

```tsx theme={null}
function DataTable({ data, isLoading }: DataTableProps) {
  if (isLoading) {
    return (
      <div className="flex items-center justify-center p-8">
        <Loader2 className="h-8 w-8 animate-spin" />
        <span className="ml-2">Loading...</span>
      </div>
    )
  }

  return <Table data={data} />
}
```

### Error States

```tsx theme={null}
function DataFetcher() {
  const [error, setError] = useState<Error | null>(null)

  if (error) {
    return (
      <Alert variant="destructive">
        <AlertCircle className="h-4 w-4" />
        <AlertTitle>Error</AlertTitle>
        <AlertDescription>{error.message}</AlertDescription>
      </Alert>
    )
  }

  return <DataDisplay />
}
```

### Empty States

```tsx theme={null}
function CompanyList({ companies }: CompanyListProps) {
  if (companies.length === 0) {
    return (
      <div className="flex flex-col items-center justify-center p-8 text-center">
        <Building2 className="h-12 w-12 text-muted-foreground mb-4" />
        <h3 className="text-lg font-semibold mb-2">No companies found</h3>
        <p className="text-sm text-muted-foreground mb-4">
          Get started by creating your first company.
        </p>
        <Button>
          <Plus className="mr-2 h-4 w-4" />
          Create Company
        </Button>
      </div>
    )
  }

  return <div>{/* Render companies */}</div>
}
```

## Form Components

### Using React Hook Form + Zod

```tsx theme={null}
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import * as z from "zod"
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"

const formSchema = z.object({
  name: z.string().min(2, "Name must be at least 2 characters"),
  email: z.string().email("Invalid email address"),
  website: z.string().url("Invalid URL").optional()
})

export function CompanyForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      name: "",
      email: "",
      website: ""
    }
  })

  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values)
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="name"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Company Name</FormLabel>
              <FormControl>
                <Input placeholder="Acme Corp" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input type="email" placeholder="contact@acme.com" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />

        <Button type="submit">Submit</Button>
      </form>
    </Form>
  )
}
```

## Server vs Client Components

### When to Use "use client"

Only add `"use client"` when you need:

* **React Hooks**: useState, useEffect, useContext, etc.
* **Browser APIs**: window, document, localStorage, etc.
* **Event Handlers**: onClick, onChange, onSubmit, etc.
* **Third-party libraries**: That use hooks or browser APIs

```tsx theme={null}
// ❌ Doesn't need "use client"
export function StaticCard({ title, description }: CardProps) {
  return (
    <div>
      <h2>{title}</h2>
      <p>{description}</p>
    </div>
  )
}

// ✅ Needs "use client"
"use client"

export function InteractiveCard({ title }: CardProps) {
  const [isOpen, setIsOpen] = useState(false)

  return (
    <div onClick={() => setIsOpen(!isOpen)}>
      <h2>{title}</h2>
      {isOpen && <p>Details</p>}
    </div>
  )
}
```

## Performance Patterns

### Lazy Loading

```tsx theme={null}
import { lazy, Suspense } from "react"

const HeavyComponent = lazy(() => import("./HeavyComponent"))

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  )
}
```

### Memoization

```tsx theme={null}
import { useMemo, useCallback } from "react"

function ExpensiveComponent({ data }: Props) {
  // Memoize expensive calculations
  const processedData = useMemo(() => {
    return data.map(item => /* expensive operation */)
  }, [data])

  // Memoize callbacks
  const handleClick = useCallback(() => {
    console.log("Clicked")
  }, [])

  return <div onClick={handleClick}>{/* render */}</div>
}
```

### React.memo

```tsx theme={null}
import React from "react"

interface Props {
  title: string
  count: number
}

// Only re-renders when props change
export const MemoizedComponent = React.memo(function Component({ title, count }: Props) {
  return (
    <div>
      <h2>{title}</h2>
      <p>Count: {count}</p>
    </div>
  )
})
```

## Accessibility Patterns

### Keyboard Navigation

```tsx theme={null}
function MenuItem({ onClick }: MenuItemProps) {
  return (
    <button
      onClick={onClick}
      onKeyDown={(e) => {
        if (e.key === "Enter" || e.key === " ") {
          onClick()
        }
      }}
    >
      Menu Item
    </button>
  )
}
```

### ARIA Labels

```tsx theme={null}
<Button aria-label="Close dialog">
  <X className="h-4 w-4" />
</Button>

<Input
  aria-label="Search companies"
  aria-describedby="search-help"
  placeholder="Search..."
/>
<p id="search-help" className="text-sm text-muted-foreground">
  Enter company name or industry
</p>
```

### Focus Management

```tsx theme={null}
function Dialog({ isOpen, onClose }: DialogProps) {
  const closeButtonRef = useRef<HTMLButtonElement>(null)

  useEffect(() => {
    if (isOpen) {
      closeButtonRef.current?.focus()
    }
  }, [isOpen])

  return (
    <DialogPrimitive.Root open={isOpen} onOpenChange={onClose}>
      {/* Dialog content */}
      <Button ref={closeButtonRef} onClick={onClose}>
        Close
      </Button>
    </DialogPrimitive.Root>
  )
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Always use cn() for className merging">
    ```tsx theme={null}
    // ✅ Good
    <div className={cn("base-class", className)} />

    // ❌ Bad
    <div className={`base-class ${className}`} />
    ```
  </Accordion>

  <Accordion title="Extract complex JSX to sub-components">
    Keep components focused and readable by extracting complex logic
  </Accordion>

  <Accordion title="Type all props">
    ```tsx theme={null}
    // ✅ Good
    interface Props {
      title: string
      onClick: () => void
    }

    // ❌ Bad
    function Component(props: any) {}
    ```
  </Accordion>

  <Accordion title="Use semantic HTML">
    ```tsx theme={null}
    // ✅ Good
    <nav><ul><li><a href="...">Link</a></li></ul></nav>

    // ❌ Bad
    <div><div><div onClick={...}>Link</div></div></div>
    ```
  </Accordion>
</AccordionGroup>

## Component Organization Template

```tsx theme={null}
// 1. Imports
import * as React from "react"
import { cn } from "@/lib/utils"
import { cva } from "class-variance-authority"

// 2. Types
interface ComponentProps {
  // Props definition
}

// 3. Constants/Variants
const componentVariants = cva(/* ... */)

// 4. Component
export function Component(props: ComponentProps) {
  // 4a. Hooks
  const [state, setState] = useState()
  const ref = useRef()

  // 4b. Derived state
  const computed = useMemo(() => {}, [])

  // 4c. Handlers
  const handleClick = useCallback(() => {}, [])

  // 4d. Effects
  useEffect(() => {}, [])

  // 4e. Render
  return <div />
}

// 5. Sub-components (if needed)
Component.Header = function Header() {}
Component.Footer = function Footer() {}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Best Practices" icon="star" href="/frontend/best-practices">
    Learn coding standards and patterns
  </Card>

  <Card title="Theme System" icon="palette" href="/frontend/theme-system">
    Understand styling and theming
  </Card>

  <Card title="Project Structure" icon="folder" href="/frontend/project-structure">
    See where components live
  </Card>

  <Card title="Tech Stack" icon="layer-group" href="/frontend/tech-stack">
    Explore component libraries
  </Card>
</CardGroup>
