This directory contains reusable UI components following the existing design system defined in src/index.css.
A flexible button component with multiple variants and sizes.
Props:
variant?: "primary" | "secondary" | "ghost" | "danger" - Visual style (default: "primary")size?: "xs" | "sm" | "md" | "lg" - Button size (default: "md")loading?: boolean - Show loading spinner (default: false)Example:
import { Button } from '@/components/common'
<Button variant="primary" size="md" onClick={handleClick}>
Click me
</Button>
<Button variant="danger" loading={isSubmitting}>
Delete
</Button>
A button designed specifically for icons with consistent sizing.
Props:
size?: "sm" | "md" | "lg" - Button size (default: "md")icon: ReactNode - Icon contentaria-label: string - Required accessibility labelExample:
import { IconButton } from "@/components/common"
;<IconButton size="md" icon={<svg>...</svg>} aria-label="Close dialog" onClick={handleClose} />
A container component with optional header, body, and footer sections.
Props:
hoverable?: boolean - Add hover effect (default: false)padding?: "none" | "sm" | "md" | "lg" - Internal padding (default: "md")Subcomponents:
CardHeader - Header section with bottom borderCardBody - Main content areaCardFooter - Footer section with top border and gray backgroundExample:
import { Card, CardHeader, CardBody, CardFooter } from "@/components/common"
;<Card hoverable padding="md">
<CardHeader>
<h3>Title</h3>
</CardHeader>
<CardBody>
<p>Content goes here</p>
</CardBody>
<CardFooter>
<button>Action</button>
</CardFooter>
</Card>
A modal dialog with backdrop and keyboard support.
Props:
isOpen: boolean - Control visibilityonClose: () => void - Close handlersize?: "sm" | "md" | "lg" | "xl" - Modal width (default: "md")closeOnEscape?: boolean - Allow ESC to close (default: true)closeOnBackdropClick?: boolean - Allow backdrop click to close (default: true)Subcomponents:
ModalHeader - Header with optional close buttonModalBody - Main content areaModalFooter - Footer with flex layout for action buttonsExample:
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from "@/components/common"
;<Modal isOpen={isOpen} onClose={handleClose} size="md">
<ModalHeader onClose={handleClose}>
<h3>Confirm Action</h3>
</ModalHeader>
<ModalBody>
<p>Are you sure you want to proceed?</p>
</ModalBody>
<ModalFooter>
<Button variant="secondary" onClick={handleClose}>
Cancel
</Button>
<Button variant="danger" onClick={handleConfirm}>
Confirm
</Button>
</ModalFooter>
</Modal>
A text input component with label, error, and icon support.
Props:
label?: string - Input label texterror?: string - Error message (adds red styling)helperText?: string - Helper text below inputinputSize?: "sm" | "md" | "lg" - Input size (default: "md")leftIcon?: ReactNode - Icon on the leftrightIcon?: ReactNode - Icon on the rightExample:
import { Input } from "@/components/common"
;<Input
label="Email"
type="email"
placeholder="Enter your email"
error={errors.email}
helperText="We'll never share your email"
leftIcon={<EmailIcon />}
/>
A select dropdown component with label and error support.
Props:
label?: string - Select label texterror?: string - Error message (adds red styling)helperText?: string - Helper text below selectselectSize?: "sm" | "md" | "lg" - Select size (default: "md")options: SelectOption[] - Array of option objectsplaceholder?: string - Placeholder optionleftIcon?: ReactNode - Icon on the leftSelectOption Type:
interface SelectOption {
value: string
label: string
disabled?: boolean
}
Example:
import { Select } from '@/components/common'
const options = [
{ value: 'option1', label: 'Option 1' },
{ value: 'option2', label: 'Option 2', disabled: true },
{ value: 'option3', label: 'Option 3' },
]
<Select
label="Choose an option"
options={options}
placeholder="Select one..."
error={errors.selection}
/>
All components use CSS utility classes defined in src/index.css:
modern-button - Base button styles with variantsmodern-icon-button - Icon button stylesmodern-card - Card container stylesmodern-input - Input field stylesImport from barrel export:
import { Button, Card, Input } from "@/components/common"
All components support className override:
<Button className="custom-class">Button</Button>
Dark mode is handled automatically through Tailwind's dark variant
Accessibility is built-in:
TypeScript support: