Components vs Blocks
Understanding how Kumo delivers different types of building blocks: versioned components you import, and copy-paste blocks you own.
The Building Block Spectrum
Not everything belongs in a design system library. Kumo distinguishes between components (shared, versioned primitives) and blocks (patterns you copy and own). Understanding this distinction helps you build applications faster while maintaining the right level of ownership.
This isn't just organizational preference—it's about responsibility. Components are primitives we maintain, test, and version. Blocks are helpful starting points that you extend and adapt to your needs.
Components
Components are the atomic, reusable UI elements that form the foundation of your application. Button, Input, Dialog, Badge—these are content-agnostic, context-agnostic building blocks designed for maximum reuse across any product.
Characteristics
- Versioned & maintained — We own the API, fix bugs, and ship updates
- Tree-shakeable — Import only what you use, no bloat
- Accessible by default — Built on Base UI primitives with proper ARIA support
- Design-system compliant — Semantic tokens, consistent variants, predictable APIs
- Agnostic — No business logic, no product-specific assumptions
How to Use
Import directly from the package:
import { Button, Input, Dialog, Badge } from "@cloudflare/kumo";
// Or use granular imports for better tree-shaking
import { Button } from "@cloudflare/kumo/components/button"; When Kumo ships a new version, you get bug fixes and improvements automatically. Your code doesn't change—just bump the version.
Blocks
Blocks are compositions of components that solve common patterns, but aren't agnostic enough to
live in the core library. PageHeader,
ResourceList—these are valuable,
reusable patterns, but they may only apply to certain products or need product-specific customization.
Characteristics
- You own it — Code lives in your project, you control the implementation
- Fully customizable — Modify anything beyond what props allow
- Composition-first — Built from Kumo components, not raw HTML
- Starting points — Patterns to extend, not constraints to work around
- Product-aware — Can include business logic, layout assumptions, specific compositions
How to Use
Install via CLI, then import from your project:
# Initialize config (first time only)
npx @cloudflare/kumo init
# List available blocks
npx @cloudflare/kumo blocks
# Install a block to your project
npx @cloudflare/kumo add PageHeader After installation, import from your local path:
// Path depends on your kumo.json blocksDir setting
// Default: src/components/kumo/
import { PageHeader } from "./components/kumo/page-header/page-header"; The block code is now yours. Customize it, extend it, break it apart—whatever your product needs.
A Practical Example
Consider a ProductCard.
It's a specific arrangement of components for a specific use case:
// This is a "block" or "recipe" - a specific composition
// of design system components for a particular pattern
<Surface className="rounded-lg p-4">
<img src={imgSrc} alt={imgAlt} className="rounded-md" />
<div className="mt-3">
<Text size="lg" weight="semibold">{title}</Text>
<Text className="text-kumo-subtle">{description}</Text>
<StarRating rating={rating} />
</div>
<div className="mt-4">
<Button variant="primary">Add to cart</Button>
</div>
</Surface>
All those components (Surface,
Text,
Button) come from
Kumo. But the specific arrangement? That's a pattern you own and customize.
Decision Framework
Asking "is this a component or a block?" really means asking about ownership and reuse:
Use a Component when...
- It's content-agnostic (works with any data)
- It's context-agnostic (works in any layout)
- Multiple products need the exact same thing
- Accessibility and consistency matter most
- You want automatic updates and maintenance
Use a Block when...
- You need to customize beyond props
- The pattern is product-specific
- It includes business logic or layout assumptions
- You want full control over implementation
- You prefer copy-paste over package dependency
Movement Between Levels
Things can move between these categories. A pattern that starts as a one-off in your application might become widely used enough to warrant extraction into a block. A block that proves universally useful might graduate to a full component.
The key principle: Things should move down into the design system rather than cluttering it with too-specific patterns that need to be weeded out later. Wait for reuse to prove itself before promoting something to a shared component.
This is why blocks exist as a middle ground. They're patterns worth sharing, but without the commitment of maintaining a versioned API. You get the starting point; you own the evolution.
Summary
| Components | Blocks | |
|---|---|---|
| Delivery | NPM package import | CLI copy to your project |
| Ownership | Kumo maintains | You own & customize |
| Updates | Automatic via version bump | Manual (re-install or merge) |
| Customization | Props & className only | Full source code access |
| Examples | Button, Input, Dialog, Badge | PageHeader, ResourceList |
Related
- Installation — Get started with Kumo
- CLI — Install blocks and access documentation
- Contributing — Add new components and blocks