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
A versatile button component with multiple variants and sizes.
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.
A text input component with focus states and validation support.
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.
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.
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.
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.
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>
)
}
Navigation components
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
Breadcrumb
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.
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.
import { Avatar } from "@/components/ui/avatar"
export default function Example() {
return (
<Avatar>
<img src="/user-avatar.jpg" alt="User" />
</Avatar>
)
}
Logo
The application logo component with configurable size and text.
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.
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
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..."
/>
)
}
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
)