Getting Started

Validation

Built-in validation is defined in field metadata and evaluated by Builder.

  • Use validation.common for operator-agnostic rules such as required values.
  • Use validation.rules for operator-specific rules.
  • Use showValidation to render built-in validation messages in the UI.
  • Use onStateChange when query data and validation state need to be read together.
Built-in validation
import '@vojtechportes/react-query-builder/styles.css';
const fields: IBuilderFieldProps[] = [
{
field: 'COMPANY_NAME',
label: 'Company name',
type: 'TEXT',
operators: ['EQUAL', 'CONTAINS'],
validation: {
common: {
required: true,
},
rules: [
{
operators: ['EQUAL', 'CONTAINS'],
minLength: 2,
maxLength: 50,
},
],
},
},
{
field: 'ORDER_TOTAL',
label: 'Order total',
type: 'NUMBER',
operators: ['EQUAL', 'BETWEEN'],
validation: {
common: {
required: true,
},
rules: [
{
operators: ['EQUAL'],
min: 0,
max: 100000,
},
{
operators: ['BETWEEN'],
range: {
common: {
min: 0,
},
requireAscending: true,
allowEqual: false,
},
},
],
},
},
];
<Builder
fields={fields}
data={data}
showValidation
onStateChange={state => {
console.log(state.isValid);
console.log(state.validation);
}}
onChange={setData}
/>;

Built-in rule types

  • Text fields support rules such as minLength and maxLength.
  • Number and date fields support boundary rules such as min, max, minDate, and maxDate.
  • List and multi-list fields support item-count constraints such as minItems and maxItems.
  • Range operators such as BETWEEN can use range validation to validate both values together.

Structural usage limits

Use usageLimit when a constraint depends on how many rules already use a field or a shared usage bucket. This is separate from value validation because it governs query structure rather than the validity of a single rule value.

Field usage limits
import '@vojtechportes/react-query-builder/styles.css';
const fields: IBuilderFieldProps[] = [
{
field: 'PRIMARY_EMAIL',
label: 'Primary email',
type: 'TEXT',
operators: ['EQUAL', 'CONTAINS'],
usageLimit: {
max: 1,
scope: 'global',
},
},
{
field: 'BILLING_CONTACT',
label: 'Billing contact',
type: 'TEXT',
operators: ['EQUAL'],
usageLimit: {
key: 'contact-field',
max: 1,
scope: 'parent',
},
},
{
field: 'SHIPPING_CONTACT',
label: 'Shipping contact',
type: 'TEXT',
operators: ['EQUAL'],
usageLimit: {
key: 'contact-field',
max: 1,
scope: 'parent',
},
},
];
<Builder
fields={fields}
data={data}
showValidation
onChange={setData}
/>;
  • max defines how many matching rules are allowed inside the selected scope.
  • scope="global" limits usage across the whole query tree.
  • scope="parent" limits usage only among sibling rules in the same immediate parent group.
  • key lets multiple different fields share the same quota bucket.
  • Exhausted fields are disabled in the field selector, and the Add Rule button is disabled when no selectable fields remain in the current scope.
  • showValidation still surfaces an issue when data arrives in an already invalid state, such as external input or text mode edits.
Custom validator
Use validator when validation depends on multiple rules, external state, or rules that are not expressible in field-level validation config or usageLimit.
API reference

Related recipes

© Vojtěch Václav Porteš 2026 - All library contents are available under the MIT license.
Loading privacy preferences...