Skip to main content

Shadcn UI Components

BodyWorks uses Shadcn UI components configured with the New York style. All UI components are located in components/ui/.

Form Components

Button

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

<Button variant="default" size="default">
  Click me
</Button>

<Button variant="destructive" size="lg">
  Delete
</Button>

<Button variant="outline" size="sm">
  Cancel
</Button>

<Button variant="ghost" size="icon">
  <Icon />
</Button>

Input

A styled input component with form validation support.
import { Input } from "@/components/ui/input";

<Input 
  type="text" 
  placeholder="Enter text"
  className="max-w-lg"
/>

// With validation
<Input 
  type="email" 
  placeholder="[email protected]"
  aria-invalid={hasError}
/>
Props:
  • Extends all native <input> attributes
  • Automatic focus ring styling
  • Validation state support via aria-invalid
  • File upload styling included
A full-featured navigation menu with nested items and keyboard support.
import {
  NavigationMenu,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuContent,
  NavigationMenuLink,
} from "@/components/ui/navigation-menu";

<NavigationMenu>
  <NavigationMenuList>
    <NavigationMenuItem>
      <NavigationMenuTrigger>Exercises</NavigationMenuTrigger>
      <NavigationMenuContent>
        <NavigationMenuLink href="/exercises">
          All Exercises
        </NavigationMenuLink>
      </NavigationMenuContent>
    </NavigationMenuItem>
  </NavigationMenuList>
</NavigationMenu>
A dropdown menu component with rich functionality.
import {
  DropdownMenu,
  DropdownMenuTrigger,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button variant="outline">Open Menu</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem>Profile</DropdownMenuItem>
    <DropdownMenuItem>Settings</DropdownMenuItem>
    <DropdownMenuSeparator />
    <DropdownMenuItem>Logout</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Layout Components

Drawer

A mobile-friendly drawer component for side navigation.
import {
  Drawer,
  DrawerTrigger,
  DrawerContent,
  DrawerHeader,
  DrawerTitle,
  DrawerClose,
} from "@/components/ui/drawer";

<Drawer>
  <DrawerTrigger asChild>
    <Button>Open Drawer</Button>
  </DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Navigation</DrawerTitle>
    </DrawerHeader>
    {/* Content */}
  </DrawerContent>
</Drawer>

Accordion

Collapsible content sections.
import {
  Accordion,
  AccordionItem,
  AccordionTrigger,
  AccordionContent,
} from "@/components/ui/accordion";

<Accordion type="single" collapsible>
  <AccordionItem value="item-1">
    <AccordionTrigger>Exercise Details</AccordionTrigger>
    <AccordionContent>
      Detailed exercise information...
    </AccordionContent>
  </AccordionItem>
</Accordion>
A responsive carousel component for image galleries.
import {
  Carousel,
  CarouselContent,
  CarouselItem,
  CarouselNext,
  CarouselPrevious,
} from "@/components/ui/carousel";

<Carousel>
  <CarouselContent>
    <CarouselItem>Slide 1</CarouselItem>
    <CarouselItem>Slide 2</CarouselItem>
    <CarouselItem>Slide 3</CarouselItem>
  </CarouselContent>
  <CarouselPrevious />
  <CarouselNext />
</Carousel>

Feedback Components

Tooltip

Contextual information on hover.
import {
  Tooltip,
  TooltipTrigger,
  TooltipContent,
  TooltipProvider,
} from "@/components/ui/tooltip";

<TooltipProvider>
  <Tooltip>
    <TooltipTrigger>Hover me</TooltipTrigger>
    <TooltipContent>
      <p>Helpful information</p>
    </TooltipContent>
  </Tooltip>
</TooltipProvider>

Sonner (Toast)

Toast notifications for user feedback.
import { toast } from "sonner";

toast.success("Exercise saved!");
toast.error("Failed to load data");
toast.info("New routine available");

toast.error("Exercise ID is required", {
  description: "Please provide an exercise ID",
});

Skeleton

Loading placeholders for content.
import { Skeleton } from "@/components/ui/skeleton";

<Skeleton className="h-12 w-12 rounded-full" />
<Skeleton className="h-4 w-[250px]" />
<Skeleton className="h-4 w-[200px]" />

Pagination

Pagination controls for list views.
import {
  Pagination,
  PaginationContent,
  PaginationItem,
  PaginationLink,
  PaginationNext,
  PaginationPrevious,
} from "@/components/ui/pagination";

<Pagination>
  <PaginationContent>
    <PaginationItem>
      <PaginationPrevious href="?page=1" />
    </PaginationItem>
    <PaginationItem>
      <PaginationLink href="?page=2">2</PaginationLink>
    </PaginationItem>
    <PaginationItem>
      <PaginationNext href="?page=3" />
    </PaginationItem>
  </PaginationContent>
</Pagination>

Custom Components

Fitness-specific components built for BodyWorks.

Exercise Card

Displays exercise information with 3D animation effects.
import { Card } from "@/components/exercise-card";

<Card
  name="Push-ups"
  image="/exercises/pushups.jpg"
  path="exercises"
  searchName="pushups"
/>

Routine Card

Displays workout routine information with title, description, and image.
import RoutineCard from "@/components/routine-card";

<RoutineCard
  routine_title="Full Body Workout"
  routine_description="A comprehensive full-body training program"
  routine_imageUrl="/routines/fullbody.jpg"
/>
Source (components/routine-card.tsx:10-48):
const RoutineCard = ({
  routine_title,
  routine_description,
  routine_imageUrl,
}: IRoutineCardProps) => {
  return (
    <CardContainer className="font-poppins">
      <CardBody className="group/card relative mx-12 mt-10 h-auto max-w-80 rounded-xl border bg-gray-50 p-6 shadow-lg dark:bg-black">
        <CardItem translateZ="50" className="text-xl font-bold">
          {routine_title}
        </CardItem>
        <CardItem as="p" translateZ="60" className="mt-2 text-sm text-neutral-500">
          {routine_description}
        </CardItem>
        <CardItem translateZ="100" rotateX={20} rotateZ={-10} className="mt-4 w-full">
          <Image
            src={routine_imageUrl}
            height="1000"
            width="1000"
            className="h-60 w-full rounded-xl object-cover"
            alt="thumbnail"
          />
        </CardItem>
      </CardBody>
    </CardContainer>
  );
};

Descripted Card

Exercise card with description preview.
import { DescriptedCard } from "@/components/descripted-card";

<DescriptedCard
  id="123"
  title="Bench Press"
  gif="/exercises/bench-press.gif"
  blog="Description: The bench press is a compound exercise..."
/>
Debounced search input component.
import { SearchBar } from "@/components/search-bar";

function ExerciseList() {
  const [query, setQuery] = useState("");

  return (
    <SearchBar getQuery={setQuery} />
  );
}

Aceternity UI Components

Advanced animated components from Aceternity UI.

3D Card

Interactive 3D card with tilt effect on mouse movement.
import { CardContainer, CardBody, CardItem } from "@/components/ui/3d-card";

<CardContainer>
  <CardBody className="bg-gray-50 p-6 rounded-xl">
    <CardItem translateZ="50" className="text-xl font-bold">
      Title
    </CardItem>
    <CardItem translateZ="100" rotateX={20} rotateZ={-10}>
      <img src="/image.jpg" alt="Image" />
    </CardItem>
  </CardBody>
</CardContainer>

Floating Dock

MacOS-style animated dock for navigation.
import { FloatingDock } from "@/components/ui/floating-dock";
import { Home, Dumbbell, Calendar } from "lucide-react";

const navItems = [
  { title: "Home", icon: <Home />, href: "/" },
  { title: "Exercises", icon: <Dumbbell />, href: "/exercises" },
  { title: "Routines", icon: <Calendar />, href: "/routines" },
];

<FloatingDock items={navItems} />

Infinite Moving Cards

Auto-scrolling card carousel for testimonials.
import { InfiniteMovingCards } from "@/components/ui/infinite-moving-cards";

const testimonials = [
  {
    quote: "This app transformed my fitness journey!",
    name: "John Doe",
    title: "Fitness Enthusiast"
  },
  // More testimonials...
];

<InfiniteMovingCards
  items={testimonials}
  direction="left"
  speed="fast"
  pauseOnHover={true}
/>

Box Reveal

Text reveal animation component.
import BoxReveal from "@/components/ui/box-reveal";

<BoxReveal>
  <h1>Welcome to BodyWorks</h1>
</BoxReveal>

Component Examples

Real-world usage examples from BodyWorks.

Exercise Grid Layout

import { Card } from "@/components/exercise-card";
import useExercises from "@/hooks/useExercises";

function ExerciseGrid() {
  const { exercises, isLoading } = useExercises(9, 1);

  if (isLoading) return <Skeleton className="h-64 w-full" />;

  return (
    <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
      {exercises?.data.map((exercise) => (
        <Card
          key={exercise.id}
          name={exercise.name}
          image={exercise.gifUrl}
          path="exercises"
        />
      ))}
    </div>
  );
}

Routine Showcase

import RoutineCard from "@/components/routine-card";
import { Carousel, CarouselContent, CarouselItem } from "@/components/ui/carousel";

function RoutineShowcase({ routines }) {
  return (
    <Carousel>
      <CarouselContent>
        {routines.map((routine) => (
          <CarouselItem key={routine.id}>
            <RoutineCard
              routine_title={routine.title}
              routine_description={routine.description}
              routine_imageUrl={routine.imageUrl}
            />
          </CarouselItem>
        ))}
      </CarouselContent>
    </Carousel>
  );
}

Theming

All components support dark mode via the theme provider.
import { ThemeProvider } from "@/components/theme-provider";
import { ModeToggle } from "@/components/mode-toggle";

function App({ children }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system">
      {children}
      <ModeToggle />
    </ThemeProvider>
  );
}
All components automatically adapt to the current theme using CSS variables and the dark: prefix.

Next Steps

React Hooks

Learn about data fetching and utility hooks

API Reference

Explore the backend API endpoints

Build docs developers (and LLMs) love