Add Components
Complete guide to adding new components to StarForge
This guide is for contributors who want to add new components to the Star Forge library itself. If you are a user looking to install components in your own project, see the Installation guide.
Directory Structure
StarForge components must follow a specific structure:
src/
├── components/
│ ├── star-forge/ # StarForge Components
│ │ ├── inputs/ # Input components
│ │ ├── alerts/ # Alert components
│ │ ├── heros/ # Hero components
│ │ ├── footer/ # Footer components
│ │ └── ... # Other components
│ └── ui/ # Base shadcn/ui components
├── hooks/
│ └── star-forge/ # Custom StarForge hooks
└── lib/
└── utils.ts # Shared utilitiesStep by Step to Create a Component
Create the Component File
Create your component in the appropriate directory within src/components/star-forge/:
// src/components/star-forge/<category>/my-component.tsx
import * as React from 'react';
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const myComponentVariants = cva('base-component-styles', {
variants: {
variant: {
default: '',
secondary: 'secondary-styles'
},
size: {
sm: 'text-sm',
md: 'text-base',
lg: 'text-lg'
}
},
defaultVariants: {
variant: 'default',
size: 'md'
}
});
interface MyComponentProps
extends React.HTMLAttributes<HTMLDivElement>,
VariantProps<typeof myComponentVariants> {
children?: React.ReactNode;
}
const MyComponent = React.forwardRef<HTMLDivElement, MyComponentProps>(
({ className, variant, size, children, ...props }, ref) => {
return (
<div
ref={ref}
className={cn(myComponentVariants({ variant, size, className }))}
{...props}
>
{children}
</div>
);
}
);
MyComponent.displayName = 'MyComponent';
export default MyComponent;Note: Only add
'use client'when the component uses React hooks or browser APIs. Many Star Forge components are server-safe by default.
Important: Do not import
@radix-ui/react-*or@base-ui/reactdirectly. Always use barrel files:import { Button } from '@/components/ui/button'.
Create the Preview
Create a demo page in src/components/star-forge-preview/<category>/my-component.tsx:
import MyComponent from '@/components/star-forge/<category>/my-component';
export default function Preview() {
return (
<div className="p-8">
<MyComponent />
</div>
);
}The preview must have a default export.
Register in registry-ui.ts
Add your component to src/registry/registry-ui.ts:
{
name: 'my-component',
author: 'EuMotta',
type: 'registry:ui',
registryDependencies: ['button'],
dependencies: ['lucide-react'],
description: 'Short description of what this block does.',
files: [
{
path: 'src/components/star-forge/<category>/my-component.tsx',
type: 'registry:ui'
}
],
example: 'src/components/star-forge-preview/<category>/my-component.tsx',
component: React.lazy(() =>
import('@/components/star-forge-preview/<category>/my-component').then(
(mod) => ({
default: mod.default
})
)
)
}Important:
registryDependenciesuse alias names (e.g.,button, notradix-button).filespoints to the source component.examplepoints to the preview component.componentmust be aReact.lazy(() => import(...))pointing to the preview.
Install Dependencies
If your component uses external dependencies, install them:
npm install <package>Then add them to the dependencies array in the registry entry.
Create MDX Documentation
Create an MDX file in content/docs/<category>/my-component.mdx:
---
title: My Component
description: What this component does
---
import { ComponentPreview } from '@/components/common/preview/component-preview';
import { extractSourceCode } from '@/lib/code';
## My Component
<ComponentPreview
name="my-component"
classNameComponentContainer="min-h-[600px]"
code={(await extractSourceCode('my-component')).code}
sourceCode={(await extractSourceCode('my-component')).sourceCode}
lang="tsx"
hasEngineChoice={true}
/>Add hasEngineChoice={true} when the block depends on dual primitives (select, avatar, button, etc.).
Build and Validate
Run these three commands in order:
npm run build:components
npm run audit:registry
npx tsc --noEmitAll three must pass before committing.
Naming Conventions
Components
- Use kebab-case for file names:
my-component.tsx - Use PascalCase for component names:
MyComponent - Follow the
category-namepattern when applicable:hero-1,alert-1,search-1
Hooks
- Use kebab-case for file names:
use-my-hook.ts - Use camelCase for hook names:
useMyHook
Barrel Exports
Components are exposed through barrel index.tsx files. The naming convention depends on the file location:
-
Components inside category folders (
src/components/star-forge/alerts/,cards/, etc.):- Export as
{Category}{N}— e.g.Alert1,Card2,Hero3 - Defined in
src/components/star-forge/{category}/index.tsx
- Export as
-
Components at the root of
star-forge/(not inside a category folder):- Export as the PascalCase file name — e.g.
Typography1,TypographyVariant1 - Defined directly in
src/components/star-forge/index.tsx
- Export as the PascalCase file name — e.g.
-
Sub-components or hooks with suffixes:
- Use descriptive suffixes — e.g.
Search1Input,Search1InputOption
- Use descriptive suffixes — e.g.
This keeps imports predictable: import { Alert1, Container1 } from '@/components/star-forge'.
Structure by Category
- Inputs: Form and input components
- Alerts: Alert and notification components
- Heros: Hero/main section components
- Footer: Footer components
- Cards: Card components
- Backgrounds: Background components
Best Practices
- Always use
'use client'for components that use React hooks - Export interfaces for TypeScript
- Use
cn()to combine classes - Document props with TypeScript
- Follow variant pattern when applicable
- Test components before adding to registry
- Use minimal dependencies - only what's necessary
Validation
After adding your component:
-
Check if TypeScript compiles:
npx tsc --noEmit -
Build the registry:
npm run build:components -
Audit for orphan dependencies:
npm run audit:registry -
Test the component locally:
npm run dev
Related Guides
Depending on what you are contributing, see the specialized guides in the Advanced section:
- Adding a New Primitive — for dual-engine primitives (Radix UI + Base UI)
- Adding a New Block — for high-level UI components
- Adding Base Variants — for Base UI install paths of existing blocks
- Maintenance & Registry — for registry builds and audits
Reusing Existing Libraries
Before creating a new component, check if you can reuse the libraries and components already existing in the project. This helps maintain consistency and reduce bundle size.
Available Libraries
The project already includes several libraries that can be used:
- shadcn/ui: Ready-to-use base UI components
- Lucide React: Various icons for interfaces
- class-variance-authority: For managing component variants
- Tailwind CSS: For styling
- Framer Motion: For animations
Checking Existing Components
Before creating, explore:
- shadcn/ui components in
src/components/ui/ - StarForge components in
src/components/star-forge/ - Custom hooks in
src/hooks/star-forge/
Benefits of Reuse
- Less code: Reduces the amount of code to maintain
- Consistency: Maintains uniform design and behavior
- Performance: Avoids dependency duplication
- Maintainability: Fewer components to maintain and update
Questions?
If you have questions about how to add components, consult the existing examples in the project or open an issue in the repository.