Contributing
@cloudflare/kumo

Contributing to Kumo

We welcome contributions to Kumo! This guide will help you get started with adding new components and blocks to the library.

Components vs Blocks vs Layouts

Components

Atomic, reusable UI elements

  • Single responsibility
  • Highly reusable
  • Minimal dependencies
  • Style-focused

Examples: Button, Input, Badge, Tabs

Blocks

Composed patterns for page layouts

  • Compose multiple components
  • Implement common patterns
  • Layout-focused
  • May include business logic

Examples: Breadcrumbs, PageHeader, Empty

Layouts

Page-level structure patterns

  • Full-page composition
  • Consistent structure
  • Responsive patterns
  • Application-wide use

Examples: DashboardPage

Creating New Components

Kumo includes a scaffolding tool that automates component creation. This ensures all components follow the same structure and are properly configured.

Run the Scaffolding Tool

From the workspace root, run:

pnpm --filter @cloudflare/kumo new-component

What the Scaffolding Tool Does

The tool automatically creates and updates several files:

  • Component file - src/components/{name}/{name}.tsx
  • Index file - src/components/{name}/index.ts
  • Story file - src/components/{name}/{name}.stories.tsx
  • Test file - src/components/{name}/{name}.test.tsx
  • Main exports - Updates src/index.ts
  • Build config - Updates vite.config.ts
  • Package exports - Updates package.json

Example

Here's what the scaffolding process looks like:

? Component name: Alert Banner

 Component scaffolded successfully!

📁 Files created:
   - src/components/alert-banner/alert-banner.tsx
   - src/components/alert-banner/index.ts
   - src/components/alert-banner/alert-banner.stories.tsx
   - src/components/alert-banner/alert-banner.test.tsx

📝 Files updated:
   - src/index.ts
   - vite.config.ts
   - package.json

💡 Import examples:
   import { AlertBanner } from "@cloudflare/kumo";
   import { AlertBanner } from "@cloudflare/kumo/components/alert-banner";

Component Naming

The scaffolding tool handles naming automatically. You can input the name in any format:

  • Spaces - "Alert Banner" → alert-banner directory, AlertBanner component
  • PascalCase - "AlertBanner" → alert-banner directory, AlertBanner component
  • kebab-case - "alert-banner" → alert-banner directory, AlertBanner component

Creating New Blocks

Blocks are higher-level components that compose multiple base components. Use the block scaffolding tool to create them:

Run the Block Scaffolding Tool

From the workspace root, run:

pnpm --filter @cloudflare/kumo new-block

What It Creates

The block scaffolding tool creates the same structure as components, but in the src/blocks directory:

  • Block file - src/blocks/{name}/{name}.tsx
  • Index file - src/blocks/{name}/index.ts
  • Story file - src/blocks/{name}/{name}.stories.tsx
  • Test file - src/blocks/{name}/{name}.test.tsx
  • Main exports - Updates src/index.ts (Blocks section)
  • Build config - Updates vite.config.ts
  • Package exports - Updates package.json

Example

? Block name: Navigation Bar

 Block scaffolded successfully!

📁 Files created:
   - src/blocks/navigation-bar/navigation-bar.tsx
   - src/blocks/navigation-bar/index.ts
   - src/blocks/navigation-bar/navigation-bar.stories.tsx
   - src/blocks/navigation-bar/navigation-bar.test.tsx

📝 Files updated:
   - src/index.ts
   - vite.config.ts
   - package.json

💡 Import examples:
   import { NavigationBar } from "@cloudflare/kumo";
   import { NavigationBar } from "@cloudflare/kumo/blocks/navigation-bar";

Creating New Layouts

Layouts are page-level components that provide consistent structure for common page patterns. Use the layout scaffolding tool:

Run the Layout Scaffolding Tool

From the workspace root, run:

pnpm --filter @cloudflare/kumo new-layout

What It Creates

The layout scaffolding tool creates the same structure as components and blocks, but in the src/layouts directory:

  • Layout file - src/layouts/{name}/{name}.tsx
  • Index file - src/layouts/{name}/index.ts
  • Story file - src/layouts/{name}/{name}.stories.tsx
  • Test file - src/layouts/{name}/{name}.test.tsx
  • Main exports - Updates src/index.ts (Layouts section)
  • Build config - Updates vite.config.ts
  • Package exports - Updates package.json

Example

? Layout name: Dashboard Page

 Layout scaffolded successfully!

📁 Files created:
   - src/layouts/dashboard-page/dashboard-page.tsx
   - src/layouts/dashboard-page/index.ts
   - src/layouts/dashboard-page/dashboard-page.stories.tsx
   - src/layouts/dashboard-page/dashboard-page.test.tsx

📝 Files updated:
   - src/index.ts
   - vite.config.ts
   - package.json

💡 Import examples:
   import { DashboardPage } from "@cloudflare/kumo";
   import { DashboardPage } from "@cloudflare/kumo/layouts/dashboard-page";

Development Workflow

After scaffolding a component, block, or layout, use the watch build setup to develop with the documentation site:

Watch Build Setup

Run these commands in separate terminals for development with HMR:

# Terminal 1: Watch mode for kumo package
pnpm --filter @cloudflare/kumo dev

# Terminal 2: Documentation site dev server
pnpm dev
  • Fast rebuild time (~400ms)
  • Validates bundle exports/imports
  • Tests actual build output
  • See components in real documentation context

Implementation Steps

  1. Implement the component/block/layout

    Edit the generated .tsx file in the kumo package.

  2. Create demo file

    Add a {Name}Demo.tsx file in kumo-docs-astro/src/components/demos/ to showcase component variants.

  3. Write tests

    Add tests to the generated .test.tsx file. Run tests in watch mode while developing.

    pnpm --filter @cloudflare/kumo test
  4. Build the package

    Before committing, do a full production build to ensure everything works:

    pnpm --filter @cloudflare/kumo build
  5. Regenerate registry

    Update the component registry to include examples from your demo file:

    pnpm --filter @cloudflare/kumo codegen:registry
  6. Add documentation page

    Create a documentation page in kumo-docs-astro/src/pages/ showing real-world usage examples.

Testing

The test suite automatically validates your component, block, or layout configuration:

  • Main entry point exports the component/block/layout
  • Deep import paths work correctly (@cloudflare/kumo/components/*, @cloudflare/kumo/blocks/*, or @cloudflare/kumo/layouts/*)
  • Package.json exports are properly configured
  • Build configuration is correct
  • All files exist in the correct locations

Run the test suite to ensure everything is configured correctly:

pnpm --filter @cloudflare/kumo test:run

The tests will provide helpful error messages with exact code snippets if any configuration is missing.

Component Guidelines

When implementing components, follow these guidelines:

  • Accessibility - Include proper ARIA attributes and keyboard navigation
  • TypeScript - Export prop types and use proper type annotations
  • Styling - Use Tailwind CSS classes and the cn utility
  • Consistency - Follow existing component patterns and naming conventions
  • Documentation - Add clear JSDoc comments and usage examples
  • Testing - Include unit tests for component behavior
  • Single Responsibility - Keep components focused on one task

Block Guidelines

When implementing blocks, follow these additional guidelines:

  • Composition - Compose existing components rather than reimplementing functionality
  • Framework Agnostic - Use LinkProvider for routing to remain framework-agnostic
  • Flexible Props - Accept both simple and complex props to support various use cases
  • Common Patterns - Focus on patterns that appear in multiple applications
  • Documentation - Include JSDoc explaining the block's purpose and when to use it
  • Examples - Provide clear usage examples showing composition

When to Create a Block

  • Pattern appears in multiple places across applications
  • Combines 2+ base components
  • Implements a common layout or page structure
  • Has specific business logic or behavior

When NOT to Create a Block

  • Single component with styling variations (use component variants instead)
  • Application-specific logic (keep in application code)
  • One-off patterns (wait for reuse before abstracting)

Additional Resources

For more detailed information, refer to: