Contributing Blocks

PreviousNext

Blocks are full screens composed from Zard components — a login page, a dashboard shell — that users copy in one go.

Each block lives in libs/blocks/src/lib/<name> and is made of three files: the Angular component, its template, and a block.ts holding the metadata the site and the CLI read. Names are conventionally suffixed with a number — login-01 , login-02 — so variations of the same idea group naturally.

Run the Generator

The generator creates the three files, exports them from libs/blocks/src/index.ts and registers the block in BLOCKS_REGISTRY . It finishes by printing the manual steps that remain.

Scaffold a block Copy
npm run generate:block
# or, non-interactively:
npx nx generate @zardui/generators:block \
  --name=login-06 \
  --description="Split login screen with a testimonial panel" \
  --category=login \
  --label=Login

--category is the registry bucket and is validated against the union below; --label is the display label stored in Block.category , and --title overrides the card heading. Passing a category that does not exist fails immediately instead of silently registering nothing.

Block Metadata

block.ts exports a single object typed as Block , imported from @doc/domain/components/block-container/block-container.component .

libs/blocks/src/lib/login-01/block.ts Copy
import type { Block } from '@doc/domain/components/block-container/block-container.component';

import { Login01Component } from './login-01.component';

export const login01Block: Block = {
  id: 'login-01',
  title: 'Login form',
  description: 'A simple login form.',
  component: Login01Component,
  category: 'Login',
  image: {
    light: '/blocks/login-01/light.png',
    dark: '/blocks/login-01/dark.png',
  },
  // Generated by `npm run sync:blocks` — do not edit by hand.
  files: [],
};
FieldTypeDescription
idstringThe folder name. Used in the preview route /blocks/preview/:id.
titlestringThe heading shown on the block card.
descriptionstringOne sentence describing what the screen does.
componentTypeThe Angular component rendered in the live preview.
categorystringA display label such as 'Authentication'. It is not the registry key.
image{ light, dark }Paths to the two screenshots served from apps/web/public/blocks/<id>/.
filesBlockFile[]The copyable sources. Generated by npm run sync:blocks — never edit by hand.

Registry & Categories

BLOCKS_REGISTRY is a record keyed by BlockCategory , declared in domain/services/blocks.service.ts . These keys are fixed:

featuredsidebarloginsignupotpcalendar
apps/web/src/app/domain/config/blocks-registry.ts Copy
import { login01Block, signup01Block } from '@blocks';

import type { BlockCategory } from '../services/blocks.service';

export const BLOCKS_REGISTRY: Record<BlockCategory, any[]> = {
  featured: [login01Block, signup01Block],
  sidebar: [],
  login: [login01Block],
  signup: [signup01Block],
  otp: [],
  calendar: [],
};
i

Why blocks appear twice

The /blocks page renders one category at a time and defaults to featured . A block registered only under its own category would never show on the landing page, so the generator adds it to featured as well — exactly how login-01 is registered today.

What You Must Add

The generator stops at the scaffold. These four steps are yours.

1
Build the screen

Compose existing Zard components in <name>.component.ts and its template. A block should not introduce new primitives — if you need one, add it to libs/zard first.

2
Sync the sources

Run npm run sync:blocks. It rewrites files[] from every .ts and .html in the folder except block.ts, so the code tab always matches the running preview.

3
Add the screenshots

Save light.png and dark.png under apps/web/public/blocks/<name>/. The generator prints the exact paths; without them the card renders a broken image.

4
Rebuild the registry

Run npm run build:registry so zard-cli and the MCP server can install the new block.

Finish the block Copy
# 1. Populate files[] from the component sources
npm run sync:blocks

# 2. Add the two screenshots the card renders
#    apps/web/public/blocks/<name>/light.png
#    apps/web/public/blocks/<name>/dark.png

# 3. Rebuild the registry consumed by the CLI
npm run build:registry
!

The screenshots are not optional

Nothing generates light.png and dark.png for you. Take them yourself at a desktop viewport, in both themes, and commit them alongside the block.

github iconwhatsapp icondiscord iconX icon

Made with in Brazil. Open source and available on GitHub .