Skip to main content

Overview

Components in this project follow a strict organizational pattern that emphasizes consistency, maintainability, and developer experience. Every component lives in its own directory with colocated CSS modules and follows kebab-case naming conventions.

Directory Structure

Each component lives in its own directory within /components/ with the following pattern:

Key Principles

  • One component per directory: Each component gets its own folder named in kebab-case
  • Named exports from index.tsx: Always export components using named exports, never default exports
  • Colocated styles: CSS modules live alongside components with the name styles.module.css
  • Colocated utilities: Component-specific utilities can be added to the component directory

Naming Conventions

All file and directory names use kebab-case throughout the project. The only exception is React component function names, which use PascalCase.

Examples

Component Definition Patterns

Function Declarations with Explicit Interfaces

Always use function declarations (not arrow functions) with explicit TypeScript interfaces:
components/button/index.tsx

Data Attributes for Variants

Use data attributes instead of multiple className conditionals for cleaner variant styling:
This pattern is cleaner than using clsx with multiple conditional classes and keeps the variant logic in CSS.

Client vs Server Components

When to Use “use client”

Only add the "use client" directive when the component needs client-side features:
required
Components using useState, useEffect, useRef, etc.
required
Access to window, localStorage, document, etc.
required
Components with onClick, onChange, or other interactive events
required
Using Motion (Framer Motion) or other animation libraries

Examples

Integration with Base UI

The project uses Base UI for headless component primitives. Components wrap Base UI components to add styling and project-specific behavior:
components/popover/index.tsx

Usage

Motion Integration

Use motion.create() to wrap Base UI components with animation capabilities:
See Motion Implementation for motion timing and easing guidelines.

Import Patterns

Use path aliases from tsconfig.json for clean imports:

Type Definitions

Component-Specific Types

Define component props interfaces in the same file:

Shared Types

Define shared types in /lib/types.ts:
lib/types.ts

Content Components

MDX content uses the same organizational pattern with colocated demos:

Demo Export Pattern

content/12-principles-of-animation/demos/index.ts
content/12-principles-of-animation/index.mdx

Best Practices

  • Keep components small and focused on a single responsibility
  • Colocate styles, utilities, and tests with components
  • Use TypeScript interfaces for all props, no any types
  • Export using named exports, not default exports
  • All files and directories use kebab-case: button-group/, use-audio.ts
  • Component implementation is always index.tsx
  • Styles are always styles.module.css
  • React functions use PascalCase: function Button()
  • Always define explicit prop interfaces
  • Avoid any type, use unknown when type is uncertain
  • Extend base component props when wrapping libraries
  • Use strict TypeScript configuration