Skip to content

Guides

Bricks

A brick is one node in a form spec — a field, a layout container, or a piece of output. Thirty ship in the box, and the registry that holds them is open: your own bricks are registered the same way and appear in the same palette.

Brick id Data type Notes
text, textarea, password string text supports masks and adornments
email, url, phone string paired with the matching validators
number number min / max / step
date, time, datetime string native pickers
select, radio string single choice
multi-select, select-boxes, tags array multiple choice
checkbox boolean inline label
signature string canvas, stored as a data URL
address object composite field
code string CodeMirror, loaded lazily
geo-point object GeoJSON Point: click the map or type latitude / longitude; Leaflet loaded lazily, OpenStreetMap tiles by default
geo-area object GeoJSON Polygon or LineString (shape): click to add vertices, drag to move, right-click to remove
geo-address object address search while typing (Nominatim by default, searchUrl with {q}), stored as a GeoJSON Feature with the normalised address and its point, adjustable on a map
geo-layer object a zone picked on a reference layer (layerUrl, GeoJSON FeatureCollection; codeProperty / nameProperty), stored as { code, name }, an array with multiple; a select lists the zones without the map
national-id string national identifier checked by idFormat: fr-nir (13 digits + key), bj-npi (10 digits), digits-<n>
mrz object machine-readable zone of a passport (2 × 44) or identity card (3 × 30): fields parsed, every ICAO 9303 check digit verified, the form refuses an inconsistent zone
tax-id string tax identifier checked by idFormat: bj-ifu (13 digits), fr-siren / fr-siret (Luhn key), digits-<n>
iban string IBAN checked with ISO 7064 mod 97-10, grouped by four on blur
money object { amount, currency }, the currency picked among currencies with currency as default
appointment object a slot { id, start, end } picked day by day, from slotsUrl (list with remaining) or generated from opening rules (days, from, to, duration, horizonDays, noticeHours, exclude)
date-range object { from, to }, the end never before the start
document object a scanned or uploaded document read by the host (services.documentReaderService, readUrl): the text read, the fields asked for (`key
measure object { value, unit, base }: a number with a unit of its family (length, area, mass, volume, duration), units restricting the choice, base holding the value in the family’s base unit (m, m², kg, l, h) so totals can mix units
vehicle-plate string registration plate checked by plateFormat (fr, bj, ci, sn, generic), upper-cased while typing and formatted on blur
company-registry string company registration number checked by registryFormat (ohada-rccm, fr-rcs, generic)
Brick id Type Notes
file input / object pluggable upload, per-brick uploadUrl, multiple mode
data-grid collection / array repeating rows with per-row validation
key-value input / object a flat object edited row by row (keyLabel, valueLabel); values take template variables from the form context like text fields
hidden input / string carries a value without rendering
Brick id Type Notes
group, row, column panel fieldset and flex containers
stepper panel wizard with per-step validation
tabs panel optional validate-before-leaving
nested-form panel references another form by specRef
content output static rich text
recap output live summary of the whole form

A searchable combobox implementing the full WAI-ARIA pattern — keyboard navigation, focus management, screen reader announcements. Options come from five sources:

optionsSource Where options come from
static a newline-separated string, or { label, value } objects
dataMap another field’s value in the same form
remote a URL, with {key} and {a.b} interpolation from context and data, plus optional server-side search
catalog a shared list resolved through optionSourceService
js a sandboxed snippet returning the list

labelKey and valueKey accept dotted paths, so name.common reads a nested property of each option object.

The row template is edited like any panel; at render time each row scopes its own data. minItems / maxItems validate the row count, rows reorder with accessible up/down buttons, and errors report as contacts[0].email.

Both gate navigation on validation. stepper validates the current step before advancing and can emit formSubmit from a final Submit button. tabs offers the same as an option, plus arrow-key navigation between tabs.

Optional prefix / suffix adornments, plus a mask config:

Mask token Accepts
9 a digit
a a letter
A a letter, upper-cased
* alphanumeric

Any other character is a literal and inserts itself — with the mask +229 99 99 99 99, the user only types digits: the prefix and the spaces appear on their own.

A live, read-only summary of everything filled so far. groupBySections turns labelled panels into titled sections, and collections render as tables — useful as the last step of a wizard.

createBrick returns a brick the registry accepts. The render function receives the brick’s props and returns a virtual node:

  1. Describe and render it.

    rating-brick.tsx
    import { createBrick, h, registerBrick } from '@streamline-pulse/formkrafter-wc'
    export const ratingBrick = createBrick({
    type: 'input',
    dataType: 'number',
    id: 'rating',
    name: 'Rating',
    category: 'Inputs',
    defaultConfigs: { label: 'Rating' },
    render: (props) =>
    h(
    'div',
    { class: { 'fk-field': true } },
    ...[1, 2, 3, 4, 5].map((star) =>
    h(
    'button',
    {
    type: 'button',
    'aria-label': `${star} stars`,
    onClick: () => props.onDataChange?.(star),
    },
    star <= Number(props.data ?? 0) ? '★' : '☆'
    )
    )
    ),
    })
  2. Register it once, before the builder mounts.

    registerBrick(ratingBrick)
  3. It now appears in the palette under its category, and renders wherever a spec uses "id": "rating".

A project by Streamline Pulse