Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/egeuysall/ryva-archive/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Ryva’s component architecture is built on shadcn/ui principles using Radix UI primitives with custom styling. Components are organized into base UI components and feature-specific compositions.

Component Categories

Base components in src/components/ui/ - styled primitives ready for composition.Examples: button.tsx, input.tsx, dialog.tsx, dropdown-menu.tsx

UI Component Library

Base Components

All UI components follow the shadcn/ui pattern:
// src/components/ui/button.tsx
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'

const buttonVariants = cva(
  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50",
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground hover:bg-primary/90',
        destructive: 'bg-destructive text-white hover:bg-destructive/90',
        outline: 'border bg-background shadow-xs hover:bg-accent',
        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-9 px-4 py-2',
        sm: 'h-8 rounded-md gap-1.5 px-3',
        lg: 'h-10 rounded-md px-6',
        icon: 'size-9',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
)

function Button({ className, variant, size, asChild = false, ...props }) {
  const Comp = asChild ? Slot : 'button'
  return <Comp className={cn(buttonVariants({ variant, size, className }))} {...props} />
}

export { Button, buttonVariants }

Available UI Components

Alert Dialog

Modal confirmation dialogs

Avatar

User profile images

Badge

Status and label indicators

Breadcrumb

Navigation breadcrumbs

Button

Interactive buttons

Card

Content containers

Checkbox

Boolean input controls

Dialog

Modal windows

Dropdown Menu

Contextual menus

Form

Form wrapper components

Input

Text input fields

Label

Form field labels

Select

Dropdown selectors

Separator

Visual dividers

Sidebar

Collapsible navigation

Skeleton

Loading placeholders

Switch

Toggle switches

Tooltip

Hover information

Component Patterns

1. Variant-Based Components

Use Class Variance Authority (CVA) for component variants:
import { cva } from 'class-variance-authority'

const badgeVariants = cva(
  "inline-flex items-center rounded-md px-2 py-1 text-xs font-medium",
  {
    variants: {
      variant: {
        default: 'bg-primary text-primary-foreground',
        secondary: 'bg-secondary text-secondary-foreground',
        destructive: 'bg-destructive text-destructive-foreground',
        outline: 'border border-input',
      },
    },
    defaultVariants: {
      variant: 'default',
    },
  }
)

2. Compound Components

Related components exported together:
// Flexible form field composition
import {
  Field,
  FieldLabel,
  FieldDescription,
  FieldError,
  FieldContent,
} from '@/components/ui/field'

function EmailField() {
  return (
    <Field orientation="vertical">
      <FieldLabel>Email</FieldLabel>
      <FieldContent>
        <Input type="email" placeholder="you@example.com" />
        <FieldDescription>
          We'll never share your email with anyone else.
        </FieldDescription>
      </FieldContent>
      <FieldError errors={errors} />
    </Field>
  )
}

3. Client Component Pattern

Next.js App Router requires explicit 'use client' for interactive components:
'use client'

import { useState } from 'react'
import { Button } from '@/components/ui/button'

export function InteractiveComponent() {
  const [count, setCount] = useState(0)
  
  return (
    <Button onClick={() => setCount(count + 1)}>
      Count: {count}
    </Button>
  )
}
Best Practice: Keep Server Components as the default. Only add 'use client' when you need:
  • React hooks (useState, useEffect, etc.)
  • Browser APIs (window, localStorage)
  • Event handlers
  • Third-party libraries that require client context

4. Composition with Slot

Use @radix-ui/react-slot for polymorphic components:
import { Slot } from '@radix-ui/react-slot'

function Button({ asChild, children, ...props }) {
  const Comp = asChild ? Slot : 'button'
  return <Comp {...props}>{children}</Comp>
}

// Usage: renders as <a> instead of <button>
<Button asChild>
  <a href="/dashboard">Go to Dashboard</a>
</Button>

Form Components

React Hook Form Integration

Forms use React Hook Form with Zod validation:
import { useForm } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
})

type FormData = z.infer<typeof schema>

function LoginForm() {
  const form = useForm<FormData>({
    resolver: zodResolver(schema),
    defaultValues: {
      email: '',
      password: '',
    },
  })

  const onSubmit = (data: FormData) => {
    console.log(data)
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)}>
        {/* form fields */}
      </form>
    </Form>
  )
}

Styling Utilities

The cn Utility

All components use the cn utility for class name merging:
// src/lib/utils.ts
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

// Usage
<div className={cn(
  "base-class",
  isActive && "active-class",
  className // Allow override from props
)} />
cn combines clsx (conditional classes) with tailwind-merge (deduplicates Tailwind classes).

Responsive Design

Tailwind breakpoints and container queries:
<div className={cn(
  "flex flex-col",                    // Mobile: column
  "md:flex-row",                      // Desktop: row
  "@md/field-group:items-center"     // Container query
)} />

Advanced Patterns

Memoization for Performance

import { useMemo } from 'react'

function TeamSwitcher() {
  const { organizations } = useOrganization()
  
  // Memoize to prevent re-renders
  const memoizedOrgs = useMemo(
    () => organizations,
    [organizations]
  )
  
  return (
    <DropdownMenu>
      {memoizedOrgs.map(org => (
        <DropdownMenuItem key={org.id}>
          {org.name}
        </DropdownMenuItem>
      ))}
    </DropdownMenu>
  )
}

Data Slots Pattern

Use data-* attributes for styling hooks:
<div
  data-slot="field"
  data-orientation={orientation}
  data-invalid={!!error}
  className="group/field data-[invalid=true]:text-destructive"
/>

Loading States

import { Skeleton } from '@/components/ui/skeleton'

function UserProfile() {
  const { data: user, isLoading } = useUser()
  
  if (isLoading) {
    return <Skeleton className="h-12 w-full" />
  }
  
  return <div>{user.name}</div>
}

Component Testing

Test components with Vitest and Testing Library:
import { render, screen } from '@testing-library/react'
import { Button } from '@/components/ui/button'

test('button renders with text', () => {
  render(<Button>Click me</Button>)
  expect(screen.getByText('Click me')).toBeInTheDocument()
})

Best Practices

Each component should have a single responsibility. Extract complex logic into custom hooks.
Always define prop types for better DX and runtime safety:
interface ButtonProps extends React.ComponentProps<'button'> {
  variant?: 'default' | 'outline'
  loading?: boolean
}
UI components should forward refs for composition:
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
  ({ className, ...props }, ref) => {
    return <button ref={ref} className={className} {...props} />
  }
)
Button.displayName = 'Button'
Use React Context or state management for deeply nested props.

Next Steps

State Management

Learn about TanStack Query and Zustand

Frontend Structure

Review the project organization