StarForge

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 utilities

Step 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/react directly. 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:

  • registryDependencies use alias names (e.g., button, not radix-button).
  • files points to the source component.
  • example points to the preview component.
  • component must be a React.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 --noEmit

All 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-name pattern 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
  • 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
  • Sub-components or hooks with suffixes:

    • Use descriptive suffixes — e.g. Search1Input, Search1InputOption

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

  1. Always use 'use client' for components that use React hooks
  2. Export interfaces for TypeScript
  3. Use cn() to combine classes
  4. Document props with TypeScript
  5. Follow variant pattern when applicable
  6. Test components before adding to registry
  7. Use minimal dependencies - only what's necessary

Validation

After adding your component:

  1. Check if TypeScript compiles:

    npx tsc --noEmit
  2. Build the registry:

    npm run build:components
  3. Audit for orphan dependencies:

    npm run audit:registry
  4. Test the component locally:

    npm run dev

Depending on what you are contributing, see the specialized guides in the Advanced section:

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:

  1. shadcn/ui components in src/components/ui/
  2. StarForge components in src/components/star-forge/
  3. 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.