Skip to main content
Biovity’s base UI components are built on top of Radix UI primitives and styled with Tailwind CSS. These components follow the shadcn/ui pattern and provide accessible, customizable building blocks for the application.

Component patterns

All UI components follow consistent patterns:
  • Const functions: Components use const ComponentName = () => {} syntax
  • Type-safe props: TypeScript prop types extend React.ComponentProps for proper typing
  • Data slots: Components use data-slot attributes for styling and testing
  • Class variance authority: Components use cva for variant-based styling
  • Composable: Complex components export multiple sub-components for flexibility

Form components

Button

A versatile button component with multiple variants and sizes.
components/ui/button.tsx
import { Button } from "@/components/ui/button"

export default function Example() {
  return (
    <div className="flex gap-2">
      <Button variant="default">Default</Button>
      <Button variant="destructive">Destructive</Button>
      <Button variant="outline">Outline</Button>
      <Button variant="ghost">Ghost</Button>
      <Button variant="link">Link</Button>
    </div>
  )
}

Props

interface ButtonProps extends React.ComponentProps<"button"> {
  variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"
  size?: "default" | "sm" | "lg" | "icon" | "icon-sm" | "icon-lg"
  asChild?: boolean
}
The asChild prop allows the button to be rendered as a child component using Radix’s Slot component, useful for rendering buttons as links.

Input

A text input component with focus states and validation support.
components/ui/input.tsx
import { Input } from "@/components/ui/input"

export default function Example() {
  return (
    <Input 
      type="text" 
      placeholder="Enter your email"
      aria-invalid={false}
    />
  )
}

Props

interface InputProps extends React.ComponentProps<"input"> {
  type?: string
  className?: string
}

Textarea

A multi-line text input component.
components/ui/textarea.tsx
import { Textarea } from "@/components/ui/textarea"

export default function Example() {
  return (
    <Textarea placeholder="Type your message here" />
  )
}

Checkbox

A checkbox component with accessible keyboard support.
components/ui/checkbox.tsx
import { Checkbox } from "@/components/ui/checkbox"

export default function Example() {
  return (
    <div className="flex items-center space-x-2">
      <Checkbox id="terms" />
      <label htmlFor="terms">Accept terms and conditions</label>
    </div>
  )
}

Select

A dropdown select component with search and keyboard navigation.
components/ui/select.tsx
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"

export default function Example() {
  return (
    <Select>
      <SelectTrigger>
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        <SelectGroup>
          <SelectLabel>Fruits</SelectLabel>
          <SelectItem value="apple">Apple</SelectItem>
          <SelectItem value="banana">Banana</SelectItem>
          <SelectItem value="orange">Orange</SelectItem>
        </SelectGroup>
      </SelectContent>
    </Select>
  )
}

Label

A form label component for accessible form inputs.
components/ui/label.tsx
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"

export default function Example() {
  return (
    <div className="flex flex-col gap-2">
      <Label htmlFor="email">Email</Label>
      <Input id="email" type="email" />
    </div>
  )
}

Field

A compound form field component combining label, input, and error message.
components/ui/field.tsx
import { Field } from "@/components/ui/field"

export default function Example() {
  return (
    <Field 
      label="Email"
      error="Please enter a valid email"
      required
    >
      <Input type="email" aria-invalid={true} />
    </Field>
  )
}

Layout components

Card

A flexible card component with composable sub-components.
components/ui/card.tsx
import {
  Card,
  CardHeader,
  CardTitle,
  CardDescription,
  CardContent,
  CardFooter,
  CardAction,
} from "@/components/ui/card"

export default function Example() {
  return (
    <Card>
      <CardHeader>
        <CardTitle>Card Title</CardTitle>
        <CardDescription>Card description goes here</CardDescription>
        <CardAction>
          <Button size="icon-sm" variant="ghost">×</Button>
        </CardAction>
      </CardHeader>
      <CardContent>
        <p>Card content goes here</p>
      </CardContent>
      <CardFooter>
        <Button>Action</Button>
      </CardFooter>
    </Card>
  )
}

Sub-components

  • CardHeader: Container for title and description with optional action
  • CardTitle: Semantic heading for the card
  • CardDescription: Muted text for additional context
  • CardAction: Action button positioned in the header
  • CardContent: Main content area with consistent padding
  • CardFooter: Footer area for actions or additional information

Separator

A visual separator for dividing content.
components/ui/separator.tsx
import { Separator } from "@/components/ui/separator"

export default function Example() {
  return (
    <div>
      <p>Content above</p>
      <Separator className="my-4" />
      <p>Content below</p>
    </div>
  )
}

Skeleton

A loading skeleton component for placeholder content.
components/ui/skeleton.tsx
import { Skeleton } from "@/components/ui/skeleton"

export default function Example() {
  return (
    <div className="flex flex-col gap-4">
      <Skeleton className="h-12 w-full" />
      <Skeleton className="h-4 w-3/4" />
      <Skeleton className="h-4 w-1/2" />
    </div>
  )
}
A dropdown menu component with nested items and keyboard navigation.
components/ui/dropdown-menu.tsx
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"

export default function Example() {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="outline">Open menu</Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent>
        <DropdownMenuLabel>My Account</DropdownMenuLabel>
        <DropdownMenuSeparator />
        <DropdownMenuItem>Profile</DropdownMenuItem>
        <DropdownMenuItem>Settings</DropdownMenuItem>
        <DropdownMenuItem variant="destructive">Logout</DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}

Sub-components

  • DropdownMenuCheckboxItem: Menu item with checkbox state
  • DropdownMenuRadioGroup: Container for radio items
  • DropdownMenuRadioItem: Menu item with radio state
  • DropdownMenuSub: Nested submenu container
  • DropdownMenuSubTrigger: Trigger for opening submenu
  • DropdownMenuShortcut: Keyboard shortcut display
A breadcrumb navigation component.
components/ui/breadcrumb.tsx
import { Breadcrumb } from "@/components/ui/breadcrumb"

export default function Example() {
  return (
    <Breadcrumb>
      <a href="/">Home</a>
      <a href="/products">Products</a>
      <span>Current Page</span>
    </Breadcrumb>
  )
}

Display components

Badge

A small badge component for labels and status indicators.
components/ui/badge.tsx
import { Badge } from "@/components/ui/badge"

export default function Example() {
  return (
    <div className="flex gap-2">
      <Badge variant="default">Default</Badge>
      <Badge variant="secondary">Secondary</Badge>
      <Badge variant="destructive">Destructive</Badge>
      <Badge variant="outline">Outline</Badge>
    </div>
  )
}

Props

interface BadgeProps extends React.ComponentProps<"span"> {
  variant?: "default" | "secondary" | "destructive" | "outline"
  asChild?: boolean
}

Avatar

An avatar component for user profile images.
components/ui/avatar.tsx
import { Avatar } from "@/components/ui/avatar"

export default function Example() {
  return (
    <Avatar>
      <img src="/user-avatar.jpg" alt="User" />
    </Avatar>
  )
}
The application logo component with configurable size and text.
components/ui/logo.tsx
import { Logo } from "@/components/ui/logo"

export default function Example() {
  return (
    <div className="flex flex-col gap-4">
      <Logo size="sm" />
      <Logo size="md" showText={true} />
      <Logo size="lg" showText={true} textSize="lg" />
    </div>
  )
}

Feedback components

Alert dialog

A modal dialog for important confirmations.
components/ui/alert-dialog.tsx
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog"

export default function Example() {
  return (
    <AlertDialog>
      <AlertDialogTrigger asChild>
        <Button variant="destructive">Delete Account</Button>
      </AlertDialogTrigger>
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle>Are you sure?</AlertDialogTitle>
          <AlertDialogDescription>
            This action cannot be undone. This will permanently delete your account.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction>Continue</AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  )
}

Disclosure components

Accordion

A collapsible accordion component.
components/ui/accordion.tsx
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "@/components/ui/accordion"

export default function Example() {
  return (
    <Accordion type="single" collapsible>
      <AccordionItem value="item-1">
        <AccordionTrigger>Is it accessible?</AccordionTrigger>
        <AccordionContent>
          Yes. It adheres to the WAI-ARIA design pattern.
        </AccordionContent>
      </AccordionItem>
      <AccordionItem value="item-2">
        <AccordionTrigger>Is it styled?</AccordionTrigger>
        <AccordionContent>
          Yes. It comes with default styles that you can customize.
        </AccordionContent>
      </AccordionItem>
    </Accordion>
  )
}

Chart components

Biovity includes a comprehensive chart system built on Recharts.

Chart container

The base container for all chart components.
components/ui/chart.tsx
import { ChartContainer, ChartConfig } from "@/components/ui/chart"
import { BarChart, Bar, XAxis, YAxis } from "recharts"

const chartConfig = {
  applications: {
    label: "Applications",
    color: "hsl(var(--primary))",
  },
} satisfies ChartConfig

export default function Example() {
  const data = [
    { month: "Jan", applications: 45 },
    { month: "Feb", applications: 52 },
    { month: "Mar", applications: 67 },
  ]

  return (
    <ChartContainer config={chartConfig}>
      <BarChart data={data}>
        <XAxis dataKey="month" />
        <YAxis />
        <Bar dataKey="applications" fill="var(--color-applications)" />
      </BarChart>
    </ChartContainer>
  )
}

Chart types

Biovity includes pre-configured chart components:
  • value-line-bar-chart.tsx: Line chart with value bars
  • stroke-multiple-radar-chart.tsx: Multi-series radar chart
  • rounded-pie-chart.tsx: Pie chart with rounded segments
  • radial-chart.tsx: Radial/circular chart
  • gradient-rounded-chart.tsx: Chart with gradient fills
  • duotone-bar-chart.tsx: Bar chart with two-tone colors
  • duotone-bar-multiple-chart.tsx: Multi-series duotone bar chart
  • dotted-multi-line.tsx: Multi-line chart with dotted lines
  • clipped-area-chart.tsx: Area chart with clipping mask

Chart tooltip and legend

import {
  ChartContainer,
  ChartTooltip,
  ChartTooltipContent,
  ChartLegend,
  ChartLegendContent,
} from "@/components/ui/chart"

export default function Example() {
  return (
    <ChartContainer config={chartConfig}>
      <BarChart data={data}>
        <ChartTooltip content={<ChartTooltipContent />} />
        <ChartLegend content={<ChartLegendContent />} />
        <Bar dataKey="applications" />
      </BarChart>
    </ChartContainer>
  )
}

Advanced components

Combobox

A searchable select component combining input and dropdown.
components/ui/combobox.tsx
import { Combobox } from "@/components/ui/combobox"

export default function Example() {
  const [value, setValue] = useState("")
  
  const options = [
    { value: "biotechnology", label: "Biotechnology" },
    { value: "chemistry", label: "Chemistry" },
    { value: "biochemistry", label: "Biochemistry" },
  ]

  return (
    <Combobox
      value={value}
      onChange={setValue}
      options={options}
      placeholder="Search field..."
    />
  )
}

Input group

A grouped input component with prefix/suffix elements.
components/ui/input-group.tsx
import { InputGroup } from "@/components/ui/input-group"
import { Search01Icon } from "@hugeicons/core-free-icons"
import { HugeiconsIcon } from "@hugeicons/react"

export default function Example() {
  return (
    <InputGroup>
      <HugeiconsIcon icon={Search01Icon} className="text-muted-foreground" />
      <Input placeholder="Search..." />
    </InputGroup>
  )
}

Animated beam

An animated beam effect component for visual interest.
components/ui/animated-beam.tsx
import { AnimatedBeam } from "@/components/ui/animated-beam"

export default function Example() {
  return (
    <div className="relative">
      <AnimatedBeam />
    </div>
  )
}

Styling conventions

All UI components follow these styling patterns:
  • Tailwind-first: All styling uses Tailwind utility classes
  • CSS variables: Colors use CSS custom properties (e.g., var(--primary))
  • Focus states: All interactive components include visible focus indicators
  • Dark mode: Components support dark mode via class-based theming
  • Responsive: Components adapt to different screen sizes
  • Aria attributes: Proper ARIA labels and roles for accessibility

Utilities

Components use the cn() utility for conditional class merging:
import { cn } from "@/lib/utils"

const className = cn(
  "base-classes",
  condition && "conditional-classes",
  props.className
)