Thank you for your interest in contributing to coss ui! This guide will help you understand how to contribute components and particles to our design system.
coss ui consists of two main types of components:
- UI Components - Core reusable components (
Button,Input, etc.) - Particles - Composite components that use or combine multiple UI components
Particles are composite components that use or combine multiple UI components. They appear in the documentation and on the particles page.
Particles use the format: p-{component}-{N}.tsx
- component: The component name (e.g.,
button,input,alert-dialog,input-group) - N: Progressive number within the category (e.g.,
1,2,3)
Examples:
p-button-1.tsx(first button particle)p-input-2.tsx(second input particle)p-pagination-1.tsx(first pagination particle)p-alert-dialog-1.tsx(first alert dialog particle)p-input-group-3.tsx(third input group particle)
Note: Component names use hyphens for multi-word components (e.g., alert-dialog, input-group, number-field).
-
Create a new file in
registry/default/particles/with the correct naming:# Example: p-button-8.tsx (8th button particle) touch registry/default/particles/p-button-8.tsx -
Export a component named
Particle:// registry/default/particles/p-button-8.tsx import { Button } from "@/registry/default/ui/button" export default function Particle() { return ( <div className="flex gap-2"> <Button variant="outline">Cancel</Button> <Button>Save Changes</Button> </div> ) }
Important notes:
- Always name the default export function
Particle(notParticleBt8or similar) - Use Base UI primitives from
@/registry/default/ui/(e.g.,input,button,label, etc.) - If a particle uses multiple UI primitives, choose the primary category for the file name
- Keep files minimal and focused
Add your particle to registry/registry-particles.ts:
// registry/registry-particles.ts
{
categories: categories("button"),
description: "Button group with cancel and save actions",
files: [{ path: "particles/p-button-8.tsx", type: "registry:block" }],
name: "p-button-8",
registryDependencies: ["@coss/button"],
type: "registry:block",
}Important fields:
name: The particle id (e.g.,p-button-8)description: Concise but descriptive (displays on particles page)type: Always"registry:block"registryDependencies: Array of UI components used (e.g.,["@coss/button"],["@coss/input", "@coss/label"])dependencies: External npm package dependencies if needed (e.g.,["lucide-react"])files: Array with one file object:path:"particles/p-button-8.tsx"type:"registry:block"
categories: Array of categories using thecategories()helper function (e.g.,categories("button"),categories("input", "label"))- Important: All valid category names are typed in
registry-categories.ts. Thecategories()helper function ensures type safety and will show TypeScript errors if you use an invalid category name. - Category names use spaces (e.g.,
"input group","alert dialog") not hyphens, as defined inregistry-categories.ts
- Important: All valid category names are typed in
meta(optional): Object withclassNameproperty for wrapper styling:meta: { className: "**:data-[slot=preview]:w-full **:data-[slot=preview]:max-w-64", }
meta.className Property:
The meta.className property adds CSS classes to the particle preview wrapper. This is useful for:
- Responsive sizing:
"**:data-[slot=preview]:w-full **:data-[slot=preview]:max-w-64" - Full width components:
"**:data-[slot=preview]:w-full" - Custom layouts and spacing
Category Naming:
- All valid category names are typed in
registry-categories.ts - Use category names that match exactly as defined in
registry-categories.ts(e.g.,"input group"not"input-group","alert dialog"not"alert-dialog") - The
categories()helper function provides type safety - TypeScript will error if you use an invalid category - For composite components, include all relevant categories
- Categories are used for filtering on the particles page
If you want to showcase the particle in documentation:
- Find the relevant MDX file in
content/docs/components/ - Add your particle with
<ComponentPreview />:
<ComponentPreview name="p-button-8" />You can also pass a className prop to override the meta className:
<ComponentPreview
name="p-button-8"
className="[&_.preview>*]:w-full [&_.preview>*]:max-w-80"
/>After adding your particle, run these scripts:
cd apps/ui
# Format code and sort imports
bun run format:all
# Build registry JSON files
bun run registry:build
## Copy UI components to the packages folder
bun run ui:syncThe registry:build command will:
- Generate
registry/__index__.tsxwith all particles - Generate
registry.jsonandpublic/r/registry.json - Build individual JSON files for each particle in
public/r/
- Use TypeScript
- Follow existing naming conventions
- Use meaningful, descriptive names
- Keep components focused and single-purpose
- Always export as
export default function Particle()
- All valid category names are typed in
registry-categories.ts - Use categories that correspond to actual components
- For composite components, include all relevant categories
- Categories are used for filtering on the particles page
- Category names must match exactly as defined in
registry-categories.ts(use spaces, not hyphens) - The
categories()helper function ensures type safety - TypeScript will error if you use an invalid category
- Keep descriptions concise but informative (≤ 15 words recommended)
- Focus on what the component does, not how it's implemented
- Descriptions appear on the particles page
- Be accurate with
dependenciesandregistryDependencies- these are used for installation registryDependenciesshould reference@coss/*package namesdependenciesshould list external npm packages (e.g.,["lucide-react"])
- Particles are numbered sequentially within each category
- If you're adding a new particle to a category, check the highest number and increment
- For example, if
p-button-26.tsxexists, the next button particle should bep-button-27.tsx
- Check existing particles for patterns and conventions
- Look at similar components for reference
- Review
registry-categories.tsfor valid category names - Ask questions in our community channels
Thank you for contributing to coss ui! 🎉