ConditionBuilder
v1.0.9Updated 19 Oct 2026Predicate builder: repeating rows of field / operator / value joined by and / or, with add and remove per row and one level of grouping (fb_3e0ed14a). The control behind "only send this automation when Department is HR and Status is not Draft". Rules are DATA - a JSON-serialisable ConditionRuleSet, controlled or uncontrolled - and ship with a dependency-free evaluator (evaluateConditionRuleSet) that runs the saved rule against a record, on the server if that is where the automation runs.
Preview
Live · 12 stories▸Why this is recommendedconditionrulefilterquery+7
The default, out-of-the-box ConditionBuilder.
- ✓Only send this automation when field X is / is not Y
- ✓Build a filter or segment out of field, operator and value rows joined by and / or
- ✓Let an admin write approval rules without writing code
- ✓An if-this-then-that condition editor on a settings screen
- ✓Saved views or smart lists a user defines themselves
- Rules are data: ConditionRuleSet = { joiner, groups: [{ id, joiner, conditions: [{ id, field, operator, value }] }] } - controlled value + onChange, or uncontrolled defaultValue
- One level of nesting: conditions share their group joiner, groups share the set joiner, so (A and B) or (C and D) is expressible and the stored shape stays a fixed two-level object, not a recursive tree
- The field's type decides the operators: text (is / contains / starts with / is empty), number (greater than / between), date (before / after / on or before), boolean (is true / is false), select and multiselect (is any of / has all of / is none of)
- The operator's arity decides the value editor: none for is empty, one for most, TWO for is between, a multi-select for is any of
- Value editors are this catalogue's own controls - Input, NumberInput, DatePicker, Select, MultiSelect - never hand-rolled
- Every control is named with its row number and its part (Condition 2 operator), so a screen reader never meets a third anonymous combo box in a repeating row
- Removing a row moves focus to the row that took its place (or the Add button) and announces itself through a polite live region
- The and / or joiner is a real radio group (arrow keys, Space), shown once per group and echoed as text after
- States: empty, disabled (controls stay, edits blocked), readOnly (the rule as sentences, no controls), an invalid row wired to its own message, and maxConditions / maxGroups ceilings that say why Add is off
- Pure helpers with no eval and no dynamic code: evaluateConditionRuleSet / evaluateCondition / filterByConditionRuleSet, conditionRuleSetIssues for the Save button, conditionValueText for a saved-rule summary - importable from lib/condition-rules so a server component can CALL them
- A field id reaches own properties only, so a stored rule cannot walk the prototype chain of the record it is evaluated against
- Dates are stored as ISO YYYY-MM-DD strings and read by their digits, so a rule means the same day in every timezone and the whole set survives JSON round-tripping
- i18n labels prop (ConditionBuilderLabels - operator names, placeholders, per-row aria-labels, announcements; {index} / {group} / {max} templates)
- ✕Designing a form (use FormBuilderCanvas)
- ✕Laying out the steps of a workflow around the condition (use RuleStep)
- ✕Quick one-click filters above a table (use FilterBar)
- ✕Free-text search (use SearchInput)
- ✕Arbitrary boolean algebra deeper than one level of grouping - the shape is deliberately two levels
Install
Ask your agent, or call the MCP tool directly. The resolved bundle is written into your project.
Usage
Tick variants in the left menu — each adds a tab with that variant’s real story source, the same code the preview above renders.
Props
fieldsThe fields conditions may be built on: { id, label, type, options?, operators?, placeholder?, min?, max?, step?, unit? }. type is text | number | date | boolean | select | multiselect
yesvalueControlled rule set
—defaultValueUncontrolled initial rule set
—onChangeFires with the FULL next rule set after every edit
—allowGroupsOffer Add group, i.e. the one level of nesting. Default true; false keeps the stored shape unchanged so it can be turned on later
—maxConditionsMaximum conditions across every group. Default unlimited
—maxGroupsMaximum groups. Default unlimited
—disabledBlock every edit while keeping the rows visible, e.g. while saving
—readOnlyRender the rule as a static sentence per row - how a saved automation reads on a detail page. Distinct from disabled
—showValidationPaint a row whose operator needs a value and has none as invalid. Default true. A row with no field yet is never painted
—sizeRow control height. Two sizes only, because the Select trigger the row is built around has no larger one
—emptyStateReplaces the built-in message when there are no conditions
—footerEndExtra controls beside Add condition
—generateIdId factory for new rows. Default: a useId-scoped counter
—labelsOverride any built-in string (operator names, placeholders, per-row aria-labels, live-region announcements, limit hints) for i18n
—