Thank you for your interest in contributing to SpaceUI! This guide will help you get started.
- Bun (v1.1.0 or later)
- Node.js 18+ (for compatibility)
- Git
-
Clone the repository
git clone https://github.com/spacedriveapp/spaceui.git cd spaceui -
Install dependencies
bun install
-
Build all packages
bun run build
-
Run the showcase app
cd examples/showcase bun run dev
spaceui/
├── packages/
│ ├── tokens/ # Design tokens & Tailwind preset
│ ├── primitives/ # Base UI components
│ ├── forms/ # react-hook-form wrappers
│ ├── ai/ # AI agent components
│ └── explorer/ # File management components
├── examples/
│ └── showcase/ # Demo app
└── .changeset/ # Versioning
-
Choose the right package
@spacedrive/primitives- Base building blocks (buttons, inputs)@spacedrive/forms- Form field wrappers@spacedrive/ai- Agent/AI components@spacedrive/explorer- File management components
-
Create the component file
// packages/primitives/src/MyComponent.tsx import { clsx } from 'clsx'; import { forwardRef } from 'react'; interface MyComponentProps { // Props here } const MyComponent = forwardRef<HTMLDivElement, MyComponentProps>( ({ className, ...props }, ref) => { return ( <div ref={ref} className={clsx('bg-app text-ink', className)} {...props} /> ); } ); MyComponent.displayName = 'MyComponent'; export { MyComponent }; export type { MyComponentProps };
-
Export from index.ts
// packages/primitives/src/index.ts export { MyComponent } from './MyComponent'; export type { MyComponentProps } from './MyComponent';
-
Add to showcase app Update
examples/showcase/src/App.tsxto demonstrate the new component.
- TypeScript: Strict mode enabled. No
anytypes. - Components: Use
forwardReffor ref forwarding. - Styling: Use Tailwind's semantic classes (e.g.,
bg-app,text-ink). - Colors: Never use
var()directly. Use semantic classes only. - Naming: PascalCase for components, camelCase for utilities.
-
Type check
bun run typecheck
-
Build
bun run build
-
Test in showcase
cd examples/showcase && bun run dev
-
Link to consuming apps (for testing integration)
# In package directory bun link # In consuming app bun link @spacedrive/primitives
We use Changesets for versioning:
# Create a changeset
bun run changeset
# Select the packages you've modified
# Describe your changesThis creates a .changeset/*.md file describing your changes.
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Add a changeset:
bun run changeset - Commit your changes
- Push to your fork and create a PR
- Ensure CI passes
- Wait for review
- All packages build successfully
- Type checking passes
- Changeset added for user-facing changes
- Components follow design system conventions
- No hardcoded colors (use semantic classes)
- No business logic - Just presentation
- Accessible - Wrap Radix primitives
- Composable - Prefer composition over configuration
- Theme-aware - Use semantic color classes
Example:
// Good - composable
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
</CardHeader>
<CardContent>Content</CardContent>
</Card>
// Bad - too many props
<Card title="Title" content="Content" showHeader />- Data via props - No internal fetching
- Callbacks for events -
onSend,onCancel, etc. - Layout-agnostic - Use flex/grid, let container constrain
- Types co-located - Export prop interfaces
- Platform-agnostic - React DOM only
- Virtual-scroll ready - Accept virtualizers
- Thumbnail contract - URL or kind identifier
Make sure you've built the packages:
bun run buildThe showcase uses workspace links, but you may need to restart the dev server:
# In examples/showcase
bun run devEnsure peer dependencies are installed:
react&react-domtailwindcss- Package-specific peers (e.g.,
react-hook-formfor forms)
- SHARED-UI-STRATEGY.md - Migration plan
- Radix UI docs - Primitives we build on
- Tailwind docs - Styling system
- CVA docs - Component variants
- Open an issue for bugs or feature requests
- Start a discussion for questions
- Join our Discord for real-time chat
Thank you for contributing!