Thank you for your interest in contributing to Object UI! This document provides guidelines and instructions for contributing to the project.
- Getting Started
- Development Setup
- Development Workflow
- Architecture Overview
- Writing Tests
- Code Style
- Commit Guidelines
- Pull Request Process
- Documentation
- Adding Components
- Troubleshooting
- Questions & Support
- Node.js 18.0 or higher
- pnpm (recommended package manager)
- Git for version control
- Basic knowledge of React, TypeScript, and Tailwind CSS
- Fork the repository on GitHub
- Clone your fork:
git clone https://github.com/YOUR_USERNAME/objectui.git cd objectui - Add upstream remote:
git remote add upstream https://github.com/objectql/objectui.git
# Install pnpm if you haven't
npm install -g pnpm
# Install project dependencies
pnpm install# Sync with upstream
git fetch upstream
git checkout main
git merge upstream/main
# Create a feature branch
git checkout -b feature/your-feature-name# Run the visual designer demo
pnpm designer
# Run the prototype example
pnpm prototype
# Run documentation site
pnpm docs:dev# Build all packages
pnpm build
# Build specific package
cd packages/core && pnpm build# Run all tests
pnpm test
# Run tests in watch mode
pnpm test:watch
# Run tests with UI (interactive)
pnpm test:ui
# Generate coverage report
pnpm test:coverage# Lint all packages
pnpm lint
# Lint specific package
cd packages/react && pnpm lintObject UI follows a modular monorepo architecture:
packages/
├── types/ # TypeScript type definitions (Zero dependencies)
├── core/ # Core logic, validation, registry (Zero React)
├── react/ # React bindings and SchemaRenderer
├── components/ # UI components (Tailwind + Shadcn)
├── designer/ # Visual schema editor
├── plugin-charts/ # Chart components plugin
└── plugin-editor/ # Rich text editor plugin
- Protocol Agnostic: Core never depends on specific backends
- Tailwind Native: All styling via Tailwind utility classes
- Type Safety: Strict TypeScript everywhere
- Tree Shakable: Modular imports, no monolithic bundles
- Zero React in Core: Core package has no React dependencies
See Architecture Documentation for details.
All tests should be placed in __tests__ directories within the source code. We use Vitest and React Testing Library.
import { describe, it, expect } from 'vitest'
import { render, screen } from '@testing-library/react'
import { MyComponent } from './MyComponent'
describe('MyComponent', () => {
it('should render correctly', () => {
render(<MyComponent />)
expect(screen.getByText('Expected Text')).toBeInTheDocument()
})
it('should handle user interaction', async () => {
const { user } = render(<MyComponent />)
await user.click(screen.getByRole('button'))
expect(screen.getByText('Clicked')).toBeInTheDocument()
})
})- Write tests for all new features
- Test user interactions, not implementation details
- Use meaningful test descriptions
- Aim for 80%+ code coverage
- Test edge cases and error states
// ✅ Good: Explicit types, clear naming
interface UserData {
id: string
name: string
email: string
}
function getUserById(id: string): UserData | null {
// implementation
}
// ❌ Bad: Implicit any, unclear naming
function get(x) {
// implementation
}// ✅ Good: TypeScript, named exports, clear props
interface ButtonProps {
label: string
onClick: () => void
variant?: 'primary' | 'secondary'
}
export function Button({ label, onClick, variant = 'primary' }: ButtonProps) {
return (
<button
onClick={onClick}
className={cn(
'px-4 py-2 rounded',
variant === 'primary' ? 'bg-blue-500' : 'bg-gray-500'
)}
>
{label}
</button>
)
}
// ❌ Bad: No types, default export, inline styles
export default function Button(props) {
return <button style={{ color: 'blue' }}>{props.label}</button>
}- Always use Tailwind: Never use inline styles or CSS modules
- Use
cn()utility: For conditional classes - Extract repeated classes: Create reusable class combinations
- Follow Shadcn patterns: Match the style of existing components
// ✅ Good
<div className={cn(
'flex items-center gap-2 p-4',
isActive && 'bg-blue-50',
className
)}>
{children}
</div>
// ❌ Bad
<div style={{ display: 'flex', padding: '16px' }}>
{children}
</div>- Use meaningful variable and function names
- Keep functions small and focused (< 50 lines)
- Add JSDoc comments for public APIs
- Avoid deep nesting (max 3 levels)
- Use early returns to reduce complexity
We follow Conventional Commits:
feat:- New featuresfix:- Bug fixesdocs:- Documentation changestest:- Adding or updating testschore:- Maintenance tasks (deps, config)refactor:- Code refactoring (no behavior change)perf:- Performance improvementsstyle:- Code style changes (formatting)
feat: add date picker component
fix: resolve schema validation error
docs: update installation guide
test: add tests for SchemaRenderer
chore: update dependencies
refactor: simplify expression evaluator<type>: <subject>
<body (optional)>
<footer (optional)>
-
Update from upstream:
git fetch upstream git rebase upstream/main
-
Create a changeset (for package changes):
pnpm changeset
This will prompt you to:
- Select which packages have changed
- Choose the version bump type (major, minor, patch)
- Write a summary of the changes
Learn more about changesets in the Versioning and Releases section.
-
Ensure tests pass:
pnpm test -
Ensure build succeeds:
pnpm build
-
Update documentation if needed
-
Add tests for new features
-
Push your branch:
git push origin feature/your-feature-name
-
Go to GitHub and create a Pull Request
-
Fill in the PR template:
- Clear description of changes
- Link to related issues
- Screenshots for UI changes
- Breaking changes (if any)
- Keep PRs focused (one feature/fix per PR)
- Write clear, descriptive PR titles
- Include before/after screenshots for UI changes
- Respond to review comments promptly
- Keep commits clean and meaningful
Our repository includes several automated GitHub workflows that will run when you create a PR:
- Linting: Checks code style and quality
- Type Checking: Validates TypeScript types
- Tests: Runs unit and integration tests
- Build: Ensures all packages build successfully
- Matrix Testing: Tests on Node.js 18.x and 20.x
- CodeQL: Scans for security vulnerabilities in code
- Dependency Scanning: Checks for known vulnerabilities in dependencies
- Auto-labeling: Automatically labels PRs based on changed files
- Bundle Size: Reports bundle size changes in PR comments
- PR Checks: Validates PR requirements and posts status
- Lockfile Auto-fix: Automatically resolves
pnpm-lock.yamlmerge conflicts
When you create a PR that has merge conflicts in pnpm-lock.yaml, our automation will:
- Detect the conflict automatically
- Regenerate the lockfile by running
pnpm install - Commit the fix back to your PR branch
- Notify you with a comment explaining what happened
What this means for you:
- No need to manually resolve
pnpm-lock.yamlconflicts - Your PR will be automatically updated with the resolved lockfile
- You can focus on code changes, not dependency conflicts
When manual resolution is needed:
If your PR has conflicts in files other than pnpm-lock.yaml, the automation will notify you with instructions for manual resolution.
- All checks must pass before merging
- Failed checks will show detailed error messages
- Some workflows (like auto-labeling) run automatically
- Review the check results and fix any issues
- Run
pnpm lintbefore committing - Run
pnpm testto catch test failures early - Run
pnpm buildto ensure successful builds - Keep dependencies up to date
- Follow TypeScript strict mode requirements
We use VitePress for documentation. All docs are in docs/.
# Start docs dev server
pnpm docs:dev
# Build docs
pnpm docs:build- Use clear, concise language
- Provide code examples for all concepts
- Include both JSON schemas and React code
- Use TypeScript for code examples
- Add practical, real-world examples
- Link to related documentation
See Documentation Guide for details.
We use Changesets for version management and automated releases.
Changesets is a tool that helps us:
- Track changes: Each PR includes a changeset file describing what changed
- Automate versioning: Automatically determine version bumps based on changesets
- Generate changelogs: Create comprehensive changelogs from changeset descriptions
- Coordinate releases: Release multiple packages together in our monorepo
Create a changeset when your PR makes changes to any package in packages/:
-
✅ DO create a changeset for:
- New features
- Bug fixes
- Breaking changes
- Performance improvements
- API changes
-
❌ DON'T create a changeset for:
- Documentation updates only
- Changes to examples or apps
- Internal refactoring with no user-facing changes
- Test updates without code changes
-
Run the changeset command:
pnpm changeset
-
Select packages: Use arrow keys and spacebar to select which packages changed
🦋 Which packages would you like to include? ◯ @object-ui/core ◉ @object-ui/react ◯ @object-ui/components -
Choose version bump type:
- Major (x.0.0): Breaking changes
- Minor (0.x.0): New features (backwards compatible)
- Patch (0.0.x): Bug fixes and minor updates
-
Write a summary: Describe what changed
Summary: Add support for custom validation rules in forms -
Commit the changeset file:
git add .changeset/*.md git commit -m "chore: add changeset"
Write clear, user-facing descriptions:
✅ Good:
- Add support for custom date formats in DatePicker
- Fix validation error in nested form fields
- Improve performance of large data grids by 50%
❌ Bad:
- Updated code
- Fixed bug
- Changes to validationThe release process is automated:
- Create PR with changes → Include a changeset file
- PR is merged → Changeset bot creates/updates a "Version Packages" PR
- Version PR is merged → Packages are automatically published to npm
You don't need to manually:
- Update version numbers
- Update CHANGELOGs
- Create Git tags
- Publish to npm
Everything is handled by the changeset automation!
# 1. Create a feature branch
git checkout -b feat/add-date-picker
# 2. Make your changes
# ... edit files ...
# 3. Create a changeset
pnpm changeset
# Select @object-ui/components
# Choose "minor" (new feature)
# Summary: "Add DatePicker component with calendar popup"
# 4. Commit everything
git add .
git commit -m "feat: add DatePicker component"
# 5. Push and create PR
git push origin feat/add-date-picker-
Define the schema in
packages/types/:export interface MyComponentSchema extends BaseSchema { type: 'my-component' title: string content: string }
-
Implement the component in
packages/components/:export function MyComponent(props: { schema: MyComponentSchema }) { return ( <div className={cn('p-4', props.schema.className)}> <h3>{props.schema.title}</h3> <p>{props.schema.content}</p> </div> ) }
-
Register the component:
registry.register('my-component', MyComponent)
-
Add tests:
describe('MyComponent', () => { it('should render title and content', () => { const schema = { type: 'my-component', title: 'Test', content: 'Content' } render(<SchemaRenderer schema={schema} />) expect(screen.getByText('Test')).toBeInTheDocument() }) })
-
Add documentation in
docs/components/my-component.md
Problem: You have merge conflicts in pnpm-lock.yaml
Solution: Our automated workflow will resolve this for you! Just wait for the bot to regenerate and commit the lockfile.
Manual Resolution (if needed):
# Update your branch with the latest changes from main
git fetch origin
git merge origin/main
# If only pnpm-lock.yaml has conflicts, regenerate it
pnpm install --no-frozen-lockfile
# Commit and push
git add pnpm-lock.yaml
git commit -m "chore: resolve pnpm-lock.yaml conflicts"
git pushProblem: pnpm install fails or dependencies are missing
Solution:
# Clear cache and reinstall
rm -rf node_modules
rm -rf .pnpm-store
pnpm store prune
pnpm installProblem: pnpm build fails with errors
Solution:
- Check TypeScript errors: Run
pnpm buildin the specific package - Ensure dependencies are installed:
pnpm install - Clear build artifacts:
rm -rf distin the package directory - Rebuild:
pnpm build
Problem: Tests are failing locally but pass in CI
Solution:
- Ensure you're on the correct Node.js version (18.x or 20.x)
- Clear test cache:
pnpm test --clearCache(if using Jest) - Update snapshots if needed:
pnpm test -u - Ensure all dependencies are installed:
pnpm install
- GitHub Discussions - General questions and ideas
- GitHub Issues - Bug reports and feature requests
- Email - hello@objectui.org
- Check if the bug is already reported
- Create a new issue with:
- Clear title and description
- Steps to reproduce
- Expected vs actual behavior
- Code examples (minimal reproduction)
- Environment details (OS, Node version, etc.)
- Check if it's already requested
- Open a discussion to gather feedback
- If approved, create an issue with detailed spec
By contributing, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to Object UI! 🎉