| name | atomic-components |
| description | Create atomic components (atoms) - basic, reusable UI building blocks following React/TypeScript best practices with Tailwind v4 styling. Use when creating fundamental UI elements like buttons, inputs, labels, icons, or other single-responsibility components. Triggers on requests like "create a button component", "add an input atom", "build a reusable icon wrapper", or "create atomic UI elements". |
Atomic Components
Create atomic components (atoms) - the fundamental building blocks of your UI with proper TypeScript interfaces and Tailwind v4 styling.
Component Structure Template
// ComponentName.tsx
// Brief description of component purpose
// always named imports from React
import { ReactNode, ReactElement, useState } from "react";
export interface ComponentNameProps {
children: ReactNode;
variant?: "primary" | "secondary"; // Variant types
size?: "small" | "medium" | "large"; // Size types
disabled?: boolean;
// Additional props
}
/**
* ComponentName component.
* Detailed description of what it does.
*/
export const ComponentName = ({
children,
variant = "primary",
size = "medium",
disabled = false,
}: ComponentNameProps): ReactElement => {
// 1. Local state (if needed)
const [isActive, setIsActive] = useState(false);
// 2. Event handlers (if needed)
const handleClick = (): void => {
if (!disabled) setIsActive(!isActive);
};
// 3. Computed variant/size classes
const getVariantClasses = (): string => {
switch (variant) {
case "secondary":
return "bg-secondary-500 text-white";
case "primary":
default:
return "bg-primary-500 text-white";
}
};
const getSizeClasses = (): string => {
switch (size) {
case "small":
return "px-3 py-1 text-sm";
case "large":
return "px-6 py-3 text-lg";
case "medium":
default:
return "px-4 py-2 text-base";
}
};
// 4. Compose final classes
const baseClasses = `
rounded-lg transition-all duration-200
${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"}
${getVariantClasses()}
${getSizeClasses()}
`;
return (
<div className={baseClasses} onClick={handleClick}>
{children}
</div>
);
}
export default ComponentName;
What Are Atoms?
Atoms are the basic building blocks of your UI - fundamental, reusable components with single responsibility.
Characteristics:
- Single responsibility (one thing, well)
- No dependencies on other components
- Highly reusable across the application
- Minimal props (typically 3-7)
- Pure presentational logic
Common Examples:
- Button with variants (primary, secondary, disabled states)
- Input field with validation states
- Typography components (Heading, Paragraph, Label)
- Icon wrapper
- Card container
- Container layout
Not Atoms (compose atoms instead):
- FormField (Label + Input + Error) → compose atoms into a molecule
- SearchBox (Input + Button) → compose atoms into a molecule
- NavigationBar (multiple atoms + logic) → compose atoms into an organism
Code Style Requirements
Import Order
- React (named imports)
- Third-party libraries
- Router/navigation
- Local API/utils
- Components
- Context/state
import { ReactNode, useState } from "react";
import { motion } from "framer-motion";
import { useNavigate } from "react-router-dom";
import { formatDate } from "../utils/dates";
import { useAuth } from "../context/AuthContext";
Type Definitions
- Always export interface for props
- Use explicit types (
string | null, neverany) - Union types for variants/states
- Optional props with
?
export interface ButtonProps {
children: ReactNode;
onClick?: () => void;
variant?: "primary" | "secondary" | "spotify";
size?: "small" | "medium" | "large";
disabled?: boolean;
type?: "button" | "submit" | "reset";
ariaLabel?: string;
}
Naming Conventions
- PascalCase: Components, interfaces
- camelCase: Functions, variables, props
- UPPER_SNAKE_CASE: Constants
- Prop naming:
onClick,isActive,hasError(verb prefixes for booleans)
Component Structure Order
// 1. Props interface
export interface ComponentProps { }
// 2. Component function with JSDoc
/**
* ComponentName brief description.
* Longer description if needed.
*/
export const ComponentName = (props: ComponentProps): ReactElement => {
// 3. State declarations
const [state, setState] = useState();
// 4. Event handlers
const handleEvent = (): void => { };
// 5. Computed values/classes
const classes = computeClasses();
// 6. Return JSX
return <div>{children}</div>;
}
// 7. Export
export default ComponentName;
Styling with Tailwind v4
Core Principles
- Use Tailwind classes, avoid inline styles
- Group related classes together
- Use template literals for conditional classes
- Extract repeated patterns into helper functions
Pattern: Variant Classes
const getVariantClasses = (): string => {
switch (variant) {
case "spotify":
return "bg-accent-500 text-primary-900 border-accent-700";
case "secondary":
return "bg-secondary-200 text-primary-900 border-secondary-700";
case "primary":
default:
return "bg-primary-500 text-primary-50 border-primary-700";
}
};
Pattern: Conditional Styling
const baseClasses = `
rounded-lg font-bold transition-all duration-200
${disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer hover:scale-105"}
${isActive && "bg-active-500"}
${getVariantClasses()}
${getSizeClasses()}
`;
Avoid v3 Patterns
Tailwind v4 Guidelines (vs v3):
- Avoid v3-era abstraction patterns
- Don't use
@applyas a component or styling system (escape hatch only) - Don't use
theme()— Tailwind v4 exposes design tokens via CSS variables - Don't over-invest in
tailwind.config.js; v4 is CSS-first, config is optional
Preferred v4 approach:
- Use utility classes directly in markup
- Use React components for reuse, not CSS abstraction
- Use CSS variables for theming when needed
Rule of thumb: If you're writing CSS to avoid utilities, you're fighting Tailwind v4.
Error Handling & Accessibility
Optional Chaining
const user = data?.user?.name ?? "Guest";
User-Facing Errors
try {
await performAction();
} catch (err: any) {
alert(`Error: ${err.message ?? "Something went wrong"}`);
}
Accessibility Props
<button
type={type}
onClick={onClick}
disabled={disabled}
aria-label={ariaLabel}
aria-pressed={isPressed}
>
{children}
</button>
Quick Reference
File Naming & Organization
ComponentName.tsx(PascalCase)- Place in
components/orcomponents/atoms/directory - One component per file
Component Checklist
- Props interface exported
- Default prop values set
- JSDoc comment present
- Tailwind v4 classes used
- Accessibility props included
- Error boundaries where needed
- Type safety (no
anyexcept external data)
Method Size Limit
Keep logic methods under 20 lines. Extract helpers if needed:
// Bad: 30-line render method with complex logic
export const Component = () => {
return (
<div>
{/* 30 lines of conditional rendering */}
</div>
);
}
// Good: Extracted to helper
export const Component = () => {
return <div>{renderContent()}</div>;
}
function renderContent(): ReactElement {
// Complex logic extracted
}
Assets
Component template available at assets/templates/AtomicComponent.tsx