Creating New Components
1. Creating a Base UI Component
Step 1: Create component file in src/components/ui/
// src/components/ui/my-component.tsx
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/cn";
const myComponentVariants = cva(
// Base classes
"base-classes-here",
{
variants: {
variant: {
default: "default-variant-classes",
secondary: "secondary-variant-classes",
},
size: {
sm: "small-size-classes",
md: "medium-size-classes",
lg: "large-size-classes",
},
},
defaultVariants: {
variant: "default",
size: "md",
},
}
);
export interface MyComponentProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof myComponentVariants> {
// Custom props
customProp?: string;
}
const MyComponent = React.forwardRef<HTMLDivElement, MyComponentProps>(
({ className, variant, size, customProp, ...props }, ref) => {
return (
<div
ref={ref}
className={cn(myComponentVariants({ variant, size, className }))}
{...props}
>
{/* Component content */}
</div>
);
}
);
MyComponent.displayName = "MyComponent";
export { MyComponent, myComponentVariants };
Step 2: Use the component
import { MyComponent } from "@/components/ui/my-component";
export function MyPage() {
return (
<MyComponent variant="default" size="md">
Content
</MyComponent>
);
}
2. Creating a Form Component
Step 1: Create form component in src/components/forms/formComponents/
// src/components/forms/formComponents/MyFieldForm.tsx
"use client";
import { useFormContext } from "react-hook-form";
import {
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
FormDescription,
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
export interface MyFieldFormProps {
name: string;
label: string;
placeholder?: string;
description?: string;
required?: boolean;
className?: string;
}
export default function MyFieldForm({
name,
label,
placeholder,
description,
required,
className,
}: MyFieldFormProps) {
const { control } = useFormContext();
return (
<FormField
control={control}
name={name}
render={({ field }) => (
<FormItem className={className}>
<FormLabel>
{label} {required && <span className="text-red-500">*</span>}
</FormLabel>
<FormControl>
<Input
{...field}
placeholder={placeholder}
value={field.value || ""}
/>
</FormControl>
{description && <FormDescription>{description}</FormDescription>}
<FormMessage />
</FormItem>
)}
/>
);
}
Step 2: Use in a form
import { useForm } from "react-hook-form";
import { Form } from "@/components/ui/form";
import MyFieldForm from "@/components/forms/formComponents/MyFieldForm";
export function MyForm() {
const form = useForm();
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<MyFieldForm
name="myField"
label="My Field"
placeholder="Enter value"
required
/>
</form>
</Form>
);
}
3. Creating a Feature Component
Step 1: Create component in feature directory
// src/components/campaign/campaign-card.tsx
"use client";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { CampaignType } from "@/types/campaign";
export interface CampaignCardProps {
campaign: CampaignType;
onEdit?: (id: string) => void;
}
export function CampaignCard({ campaign, onEdit }: CampaignCardProps) {
return (
<Card>
<CardHeader>
<CardTitle>{campaign.campaignName}</CardTitle>
</CardHeader>
<CardContent>
<p>{campaign.jurisdictionName}</p>
{onEdit && (
<Button onClick={() => onEdit(campaign.id)}>Edit</Button>
)}
</CardContent>
</Card>
);
}