Thank you for your interest in contributing to Care UI! This guide will help you add or modify components.
Care UI uses a structured workflow to maintain component quality and registry compatibility.
- Node.js: 22.16.0 (specified in
.nvmrc) - pnpm: 10.11.1 (specified in
package.json)
Install dependencies:
pnpm installThis project deploys to Cloudflare Pages. The build configuration requires:
- Node.js version: Automatically detected from
.nvmrcfile (22.16.0) - pnpm version: Set the environment variable in Cloudflare Pages dashboard:
PNPM_VERSION=10.11.1
Build Settings (Cloudflare Pages Dashboard):
- Build command:
pnpm run build - Build output directory:
dist - Root directory:
/(project root)
Configuration Files:
.nvmrc: Specifies Node.js version (22.16.0)wrangler.toml: Configures Cloudflare Pages deployment with static assets fromdistdirectory
Note: The .nvmrc file is used instead of .tool-versions because Cloudflare Pages doesn't reliably support asdf's .tool-versions format. For pnpm, you must set the PNPM_VERSION environment variable in the Cloudflare Pages dashboard under Settings → Environment Variables.
Create your component in src/components/ui/:
// src/components/ui/my-component.tsx
/**
* @name my-component
* @description A brief description of what it does
* @dependencies package-name-if-any
* @type registry:ui
*/
import { cn } from "@/lib/utils"
export function MyComponent({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn("base-styles", className)}
{...props}
/>
)
}Add documentation in src/lib/registry/:
// src/lib/registry/my-component.tsx
import React from 'react'
import { type ComponentDoc } from '@/lib/types'
import { MyComponent } from '@/components/ui/my-component'
export const myComponentDoc: ComponentDoc = {
id: 'my-component',
name: 'MyComponent',
description: 'Description of your component',
preview: {
component: <MyComponent>Preview</MyComponent>,
code: `<MyComponent>Example</MyComponent>`
},
examples: [
{
name: 'Basic Usage',
description: 'Simple example',
preview: <MyComponent />,
code: `<MyComponent />`
}
],
props: [
{
name: 'className',
type: 'string',
description: 'Additional CSS classes'
}
]
}Update src/lib/registry/index.ts:
export { myComponentDoc } from './my-component'
// Add to componentLoaders
const componentLoaders = {
// ... existing components
'my-component': () => import('./my-component').then(m => m.myComponentDoc),
}# Generate shadcn-compatible JSON files
npx tsx scripts/generate-registry.ts
# Copy to public directory
cp -r registry/care-ui public/registry/# Start dev server
pnpm dev
# Visit http://localhost:5173
# Navigate to your component in the sidebar
# Verify preview, code, examples, and props display correctlygit add .
git commit -m "Add my-component"
git pushWhen updating components, follow these steps:
# 1. Edit component source
# src/components/ui/button.tsx
# 2. Update documentation (if needed)
# src/lib/registry/button.tsx
# 3. Regenerate registry
npx tsx scripts/generate-registry.ts && \
cp -r registry/care-ui public/registry/
# 4. Test changes
pnpm dev
# 5. Commit and deploy
git add . && \
git commit -m "Update button component" && \
git pushOne-liner for quick updates:
npx tsx scripts/generate-registry.ts && \
cp -r registry/care-ui public/registry/ && \
git add . && \
git commit -m "Update components" && \
git pushThe generated JSON under public/registry/care-ui/** must always match the
component source. After editing a component, run pnpm build:registry and
commit the regenerated files. To confirm there is no drift:
pnpm registry:checkThis regenerates the registry and fails (exit 1) if any committed JSON differs
from the current source — meaning someone changed a component without running
pnpm build:registry. The fix is to run pnpm build:registry and commit the
updated files. Run pnpm registry:check before opening a PR.
✅ Always edit:
src/components/ui/[component].tsx- Component source codesrc/lib/registry/[component].tsx- Component documentationsrc/lib/registry/index.ts- Registry exports
❌ Never manually edit:
registry/care-ui/**/*.json- Auto-generated by scriptpublic/registry/care-ui/**/*.json- Copied from registry/
✅ DO:
// Use semantic HTML
<button type="button" {...props}>Click me</button>
// Include proper TypeScript types
interface MyComponentProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: 'default' | 'outline'
}
// Support className merging
className={cn("base-classes", className)}
// Add accessibility attributes
<button aria-label="Close" aria-pressed={isPressed}>❌ DON'T:
// Hardcode styles without className support
<div style={{ color: 'red' }}>Bad</div>
// Forget to export from registry index
// Always add to src/lib/registry/index.ts- Include clear descriptions
- Provide multiple examples
- Document all props with types
- Add accessibility notes when relevant
- Show common use cases
All components should:
- Support keyboard navigation
- Include proper ARIA attributes
- Work with screen readers
- Meet WCAG AA color contrast standards
- Provide focus indicators
Once deployed, users can install components:
# Install via shadcn CLI
npx shadcn@latest add https://careui.ohc.network/registry/care-ui/my-component/my-component.jsonComponents will be installed to components/careui/ in the user's project:
import { MyComponent } from "@/components/careui/my-component"Check the Contributing page in the documentation for detailed examples and guidance.