Kumo

@cloudflare/kumo

Contributing

Learn how to contribute to Kumo by adding new components and features.

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: ResourceListPage, 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
  • 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.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
  • 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.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";

📝 Note: Blocks are higher-level components that compose base components.

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
  • 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.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";

📝 Note: Layouts are page-level components for consistent structure.

Development Workflow

After scaffolding a component, block, or layout, follow these steps:

  1. Implement the component/block/layout

    Edit the generated .tsx file with your implementation. Use Storybook for rapid development.

  2. Create stories

    Add a .stories.tsx file to showcase component variants in Storybook.

  3. Write tests

    Add tests to the generated .test.tsx file.

  4. Run tests
    pnpm --filter @cloudflare/kumo test
  5. Build the package
    pnpm --filter @cloudflare/kumo build
  6. Add documentation

    Create a documentation page in kumo-docs/app/routes/

Storybook Development

Kumo uses Storybook as a live development environment for building and testing components in isolation. It provides instant feedback and serves as interactive documentation.

Start Storybook

pnpm --filter @cloudflare/kumo storybook

Opens at http://localhost:6006 with hot module replacement enabled.

Why Use Storybook

  • Build components without running the full application
  • Test all variations and edge cases interactively
  • Auto-generated documentation from TypeScript types
  • Instant HMR updates as you code
  • Shared tool for designers and developers

Creating Stories

Story files live alongside components and follow the pattern {name}.stories.tsx:

import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './button';

const meta = {
  title: 'Components/Button',
  component: Button,
  tags: ['autodocs'],
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
  args: { children: 'Click me' },
};

Story Organization

  • Components - src/components/{name}/{name}.stories.tsx
  • Blocks - src/blocks/{name}/{name}.stories.tsx
  • Layouts - src/layouts/{name}/{name}.stories.tsx

Best Practice: Always create stories for new components, blocks, and layouts. Stories serve as living documentation and make development faster.

For comprehensive Storybook documentation, see packages/kumo/STORYBOOK.md

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: