Thank you for your interest in contributing to ZardUI! This guide will help you understand how the project is structured and how you can contribute effectively.
- ✅ Requirements
- 🚀 Initial Setup
- 🏗️ Project Architecture
- 📁 Folder Structure
- 🧩 Developing Components
- 📝 Documentation System
- 🧪 Testing
- 🌿 Branch Strategy
- 🔄 Contribution Workflow
- 📋 Commit Patterns
- 🔧 Essential Commands
- Node.js version
20or22(specified inengines) - npm (included with Node.js)
- Git for version control
💡 Tip: Use
nvmto manage Node.js versions:nvm use # Uses the version specified in .nvmrc
-
Fork and clone the repository:
git clone https://github.com/[your-username]/zardui.git cd zardui -
Install dependencies:
npm install
-
Start the development environment:
npm start
The project will run at
http://localhost:4222
ZardUI is a monorepo managed by Nx with the following characteristics:
- Unified workspace with intelligent caching and dependency graph
- Conventional commits for automated releases
- Path aliases:
@zard/*→libs/zard/src/lib/* - Optimized builds with parallel task execution
- Standalone and publishable Angular library
- Components with signal-based inputs (
input()) - CVA (Class Variance Authority) for typed variants
- OnPush change detection for performance
- Host binding for dynamic classes
- Angular application that consumes the library
- Interactive documentation with live demos
- SSG (Static Site Generation) for performance
- Automatic file synchronization system
zardui/
├── libs/zard/ # 📦 Main library
│ ├── src/lib/components/ # 🧩 Components
│ │ └── [component-name]/ # 📂 Component folder
│ │ ├── [component].component.ts # 🎯 Main component
│ │ ├── [component].variants.ts # 🎨 CVA variants
│ │ ├── [component].spec.ts # 🧪 Tests
│ │ ├── demo/ # 📋 Demos for docs
│ │ │ ├── [component].ts # 📤 Main export
│ │ │ ├── default.ts # 🏠 Default example
│ │ │ └── [variant].ts # 🔀 Variant examples
│ │ └── doc/ # 📖 Documentation
│ │ ├── overview.md # 📝 Overview
│ │ └── api.md # 🔧 API reference
│ └── src/lib/shared/utils/ # 🛠️ Shared utilities
├── apps/web/ # 🌐 Documentation site
│ ├── src/app/ # 📱 Angular application
│ └── public/components/ # 📁 Synced files
├── scripts/ # 🤖 Automation scripts
│ ├── generate-files.cts # 🔄 Demo/docs sync
│ └── generate-installation-guides.cts # 📋 Installation guides
└── packages/ # 📦 Library builds
import { Component, ChangeDetectionStrategy, computed, input } from '@angular/core';
import { mergeClasses } from '@zard/shared/utils';
import { [componentName]Variants, type [ComponentName]Variants } from './[component-name].variants';
@Component({
selector: 'z-[name], [z-[name]]',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
host: { '[class]': 'classes()' },
template: `<!-- template here -->`
})
export class Zard[Name]Component {
readonly variant = input<[ComponentName]Variants['variant']>('default');
readonly size = input<[ComponentName]Variants['size']>('default');
readonly class = input<string>('');
protected readonly classes = computed(() =>
mergeClasses([componentName]Variants({
variant: this.variant(),
size: this.size()
}), this.class())
);
}- Create component in
libs/zard/src/lib/components/[name]/ - Implement variants with CVA in
[component].variants.ts - Write tests in
[component].spec.ts - Add to barrel export in
libs/zard/src/lib/components/components.ts - Create demos in the
demo/folder following existing patterns - Write documentation in
doc/overview.mdanddoc/api.md - Watch system automatically syncs to the website
- TailwindCSS v4 with PostCSS for styles
- Class merging with
tailwind-mergeto resolve conflicts - Utility-first approach for consistency
- Design tokens through CSS custom properties
The scripts/generate-files.cts script monitors changes in:
libs/zard/src/lib/components/*/demo/→apps/web/public/components/*/demo/libs/zard/src/lib/components/*/doc/→apps/web/public/components/*/doc/
// demo/default.ts
export const DefaultExample = {
name: 'Default',
code: `<z-button>Click me</z-button>`,
component: () => import('./default.component').then(m => m.DefaultComponent),
};- overview.md: Overview, use cases, basic examples
- api.md: Complete API reference, props, events, methods
- Jest with
@happy-dom/jest-environment - Angular Testing Utilities (TestBed, ComponentFixture)
- Co-located tests next to components
# Run all tests
npm test
# Watch mode
npm run test:watchimport { ComponentFixture, TestBed } from '@angular/core/testing';
import { ZardButtonComponent } from './button.component';
describe('ZardButtonComponent', () => {
let component: ZardButtonComponent;
let fixture: ComponentFixture<ZardButtonComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ZardButtonComponent],
}).compileComponents();
fixture = TestBed.createComponent(ZardButtonComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});Following the proposed workflow, we use a simplified flow:
master- 🚀 Single main branch- Receives direct PRs
- Automatic squash merge
- Automatic release via tags
- Continuous deployment to production
Naming convention:
feat/#<issue-number>-<descriptive-name>
# Example: feat/#42-button-loading
bugfix/#<issue-number>-<descriptive-name>
# Example: bugfix/#43-input-focus-bug- 📋 Fork the repository
- 🌿 Create branch directly from
master:git checkout master git pull origin master git checkout -b feat/#123-new-feature - 💻 Develop with as many commits as you want
- 🧪 Run tests:
npm test npm run test:watch # during development
- 🚀 Open PR to
master - 👁️ Review + Merge = Automatic release
- ✅ Automatic squash merge transforms multiple commits into 1 clean commit
- Tests passing -
npm test - Code follows project patterns
- Documentation updated (if necessary)
- Demos working correctly
- No lint/typecheck warnings
- Related issue linked
- Conventional commit in PR title
- Squash merge will be applied automatically
We use Conventional Commits with Emojis for better visual feedback and automated releases.
Make commits using the standard git command with the emoji + type format:
git add .
git commit -m "✨ feat(button): add new variant"| Emoji | Type | Description | Version Bump |
|---|---|---|---|
| ✨ | feat |
New functionality | Minor (0.x.0) |
| 🐛 | fix |
Bug correction | Patch (0.0.x) |
| 🚀 | perf |
Performance improvements | Patch (0.0.x) |
| ⏪️ | revert |
Revert previous commit | Patch (0.0.x) |
| 📦 | refactor |
Code refactoring | No release |
| 🧪 | test |
Tests | No release |
| 📝 | docs |
Documentation | No release |
| 💄 | style |
Code style | No release |
| 🏗️ | build |
Build system | No release |
| 🔧 | chore |
Maintenance | No release |
Breaking Changes: Add ! after the type for a Major version bump:
✨ feat(button)!: redesign button API # Major: 1.0.0 → 2.0.0We use Husky + commitlint to validate commits automatically:
- ✅ Before commit: lint-staged runs ESLint and Prettier
- ✅ On commit message: commitlint validates format
- ❌ Invalid format → commit rejected with helpful error
emoji type(scope): description
[optional body]
[optional footer]
Examples:
✨ feat(button): add loading state
🐛 fix(input): resolve focus bug
📦 refactor(dialog): improve animation performance
🧪 test(form): add validation tests
📝 docs(readme): update installation guideImportant - Emoji is REQUIRED:
- ✅ Emoji at the start (MANDATORY - commit will be rejected without it)
- ✅ Type (feat, fix, etc)
- ⚪ Scope in parentheses (optional)
- ✅ Colon and space
- ✅ Clear, imperative description
Examples of valid commits:
✅ ✨ feat(button): add variant
✅ 🐛 fix: resolve bug
✅ 📦 refactor(core): improve performance
❌ feat(button): missing emoji - WILL BE REJECTED
❌ feat: missing emoji - WILL BE REJECTEDnpm start # 🚀 Start dev server (port 4222)
npm run watch:files # 👀 Monitor changes in demos/docs
npm run build # 🏗️ Production build
npm run build:dev # 🛠️ Development buildnpm test # 🧪 All tests
npm run test:watch # 👁️ Tests in watch mode- Issues: Report bugs or request features
- Discussions: General discussions and questions
- Email: For specific questions → gomesluiz.dev@gmail.com
Our release system is fully automated - you don't need to do anything special! Here's what happens:
# Example PR with commits:
✨ feat(button): add loading variant
🐛 fix(input): resolve focus issue
📦 refactor(dialog): improve performanceThe auto-release workflow automatically:
- ✅ Analyzes commits since last release
- ✅ Determines version bump (major/minor/patch)
- ✅ Skips if only docs/chore commits
If release is needed, it automatically:
- ✅ Bumps version in
package.json - ✅ Generates/updates
CHANGELOG.md - ✅ Creates git commit:
🔖 chore(release): publish X.Y.Z - ✅ Creates git tag:
zard@X.Y.Z - ✅ Pushes to GitHub
The tag push triggers release.yml:
- ✅ Builds packages
- ✅ Publishes to npm
- ✅ Creates GitHub Release with notes
| Commits in PR | Version Bump | Example |
|---|---|---|
Only feat |
Minor | 1.2.3 → 1.3.0 |
Only fix |
Patch | 1.2.3 → 1.2.4 |
feat + fix |
Minor | 1.2.3 → 1.3.0 |
Any with ! |
Major | 1.2.3 → 2.0.0 |
Only docs, chore, etc |
None | No release |
Nothing! Just:
- ✅ Use proper commit format (emoji + type)
- ✅ Get your PR reviewed and approved
- ✅ Squash & merge to master
- ✅ Automation handles the rest!
- 📊 GitHub Actions: Check the "Actions" tab for release status
- 📝 CHANGELOG.md: Auto-updated with each release
- 🏷️ GitHub Releases: Created automatically with notes
- 📦 npm: Published automatically
If you need to create a release manually:
# Dry run (preview)
npm run release:dry-run
# Create release
npm run release
# Create specific version
npx nx release version 1.2.3- Automatic: Every merge to master (if needed)
- No schedule: Releases happen when features/fixes are ready
- Fast: Release created within ~2 minutes of merge
- Current: Angular 20 actively supported
- Previous: Angular 19 actively supported
- LTS: Angular 18 with bug fixes only
- Migration: Documented in CHANGELOG when dropping support
Questions? Open an issue or get in touch! Your contribution is very welcome! 🎉