react-querybuilder



Getting Started
npm install react-querybuilder --save
OR
yarn add react-querybuilder
Demo
See live demo
OR
To run the demo yourself, go through the following steps:
npm install
Install npm packagesnpm start
Run a local server- http://localhost:8080/ Visit your localhost in your browser
Usage
import QueryBuilder from 'react-querybuilder';
const fields = [
{ name: 'firstName', label: 'First Name' },
{ name: 'lastName', label: 'Last Name' },
{ name: 'age', label: 'Age' },
{ name: 'address', label: 'Address' },
{ name: 'phone', label: 'Phone' },
{ name: 'email', label: 'Email' },
{ name: 'twitter', label: 'Twitter' },
{ name: 'isDev', label: 'Is a Developer?', defaultValue: false }
];
const dom = <QueryBuilder fields={fields} onQueryChange={logQuery} />;
function logQuery(query) {
console.log(query);
}
API
The default export of this library is the <QueryBuilder />
React component. Named exports include the <Rule />
component (for use in custom <RuleGroup />
implementations) and a utility function, formatQuery
.
QueryBuilder
<QueryBuilder />
supports the following properties:
query
(Optional)
{id?: string, combinator: string, rules: ({field: string, value: any, operator: string} | {rules: ...[], combinator: string})[]}
The initial query, in JSON form (follows the same format as the parameter passed to the onQueryChange
callback). id
is optional. See the demo source for examples.
fields
(Required)
The array of fields that should be used. Each field should be an object with the following signature:
interface Field {
id?: string;
name: string;
label: string;
operators?: { name: string; label: string; }[];
valueEditorType?: 'text' | 'select' | 'checkbox' | 'radio' | null;
inputType?: string | null;
values?: { name: string; label: string; }[];
defaultValue?: any;
}
Field objects can also contain other data. Each field object will be passed to the appropriate OperatorSelector
and ValueEditor
components as fieldData
(see the section on controlElements
).
operators
(Optional)
{name: string, label: string}[]
The array of operators that should be used. The default operators include:
[
{ name: '=', label: '=' },
{ name: '!=', label: '!=' },
{ name: '<', label: '<' },
{ name: '>', label: '>' },
{ name: '<=', label: '<=' },
{ name: '>=', label: '>=' },
{ name: 'contains', label: 'contains' },
{ name: 'beginsWith', label: 'begins with' },
{ name: 'endsWith', label: 'ends with' },
{ name: 'doesNotContain', label: 'does not contain' },
{ name: 'doesNotBeginWith', label: 'does not begin with' },
{ name: 'doesNotEndWith', label: 'does not end with' },
{ name: 'null', label: 'is null' },
{ name: 'notNull', label: 'is not null' },
{ name: 'in', label: 'in' },
{ name: 'notIn', label: 'not in' }
];
combinators
(Optional)
{name: string, label: string}[]
The array of combinators that should be used for RuleGroups. The default set includes:
[
{ name: 'and', label: 'AND' },
{ name: 'or', label: 'OR' }
];
controlElements
(Optional)
interface Controls {
addGroupAction?: React.ComponentType<ActionWithRulesProps>;
addRuleAction?: React.ComponentType<ActionWithRulesProps>;
combinatorSelector?: React.ComponentType<CombinatorSelectorProps>;
fieldSelector?: React.ComponentType<FieldSelectorProps>;
notToggle?: React.ComponentType<NotToggleProps>;
operatorSelector?: React.ComponentType<OperatorSelectorProps>;
removeGroupAction?: React.ComponentType<ActionWithRulesProps>;
removeRuleAction?: React.ComponentType<ActionProps>;
rule?: React.ComponentType<RuleProps>;
ruleGroup?: React.ComponentType<RuleGroupProps>;
valueEditor?: React.ComponentType<ValueEditorProps>;
}
This is a custom controls object that allows you to override the control elements used. The following control overrides are supported:
addGroupAction
: By default a <button />
is used. The following props are passed:
interface ActionWithRulesProps {
label: string;
title: string;
className: string;
handleOnClick: (e: React.MouseEvent) => void;
rules: (RuleGroupType|RuleType)[];
level: number;
}
removeGroupAction
: By default a <button />
is used. The following props are passed:
interface ActionWithRulesProps {
label: string;
title: string;
className: string;
handleOnClick: (e: React.MouseEvent) => void;
rules: (RuleGroupType|RuleType)[];
level: number;
}
addRuleAction
: By default a <button />
is used. The following props are passed:
interface ActionWithRulesProps {
label: string;
title: string;
className: string;
handleOnClick: (e: React.MouseEvent) => void;
rules: (RuleGroupType|RuleType)[];
level: number;
}
removeRuleAction
: By default a <button />
is used. The following props are passed:
interface ActionProps {
label: string;
title: string;
className: string;
handleOnClick: (e: React.MouseEvent) => void;
level: number;
}
combinatorSelector
: By default a <select />
is used. The following props are passed:
interface CombinatorSelectorProps {
options: { name: string; label: string; }[];
value: string;
className: string;
handleOnChange: (value: any) => void;
rules: (RuleGroupType|RuleType)[];
level: number;
}
fieldSelector
: By default a <select />
is used. The following props are passed:
interface FieldSelectorProps {
options: Field[];
value: string;
title: string;
operator: string;
className: string;
handleOnChange: (value: any) => void;
level: number;
}
operatorSelector
: By default a <select />
is used. The following props are passed:
interface OperatorSelectorProps {
field: string;
fieldData: Field;
options: { name: string; label: string; }[];
value: string;
title: string;
className: string;
handleOnChange: (value: any) => void;
level: number;
}
valueEditor
: By default an <input type="text" />
is used. The following props are passed:
interface ValueEditorProps {
field: string;
fieldData: Field;
operator: string;
value: string;
title: string;
handleOnChange: (value: any) => void;
type: 'text'|'select'|'checkbox'|'radio';
inputType: string;
values: any[];
level: number;
className: string;
}
notToggle
: By default, <label><input type="checkbox" />Not</label>
is used. The following props are passed:
interface NotToggleProps {
checked: boolean;
handleOnChange: (checked: boolean) => void;
title: string;
level: number;
className: string;
}
ruleGroup
: By default, <RuleGroup />
is used. The following props are passed:
interface RuleGroupProps {
id: string;
parentId: string;
combinator: string;
rules: (RuleType | RuleGroupType)[];
translations: Translations;
schema: Schema;
not: boolean;
}
rule
: By default, <Rule />
is used. The following props are passed:
interface RuleProps {
id: string;
parentId: string;
field: string;
operator: string;
value: any;
translations: Translations;
schema: Schema;
}
The Schema
object passed in the rule
and ruleGroup
props has the following signature:
interface Schema {
fields: Field[];
classNames: Classnames;
combinators: { name: string; label: string }[];
controls: Controls;
createRule(): RuleType;
createRuleGroup(): RuleGroupType;
getLevel(id: string): number;
getOperators(field: string): Field[];
getValueEditorType(field: string, operator: string): 'text'|'select'|'checkbox'|'radio';
getInputType(field: string, operator: string): string | null;
getValues(field: string, operator: string): { name: string; label: string; }[];
isRuleGroup(ruleOrGroup: RuleType | RuleGroupType): ruleOrGroup is RuleGroupType;
onGroupAdd(group: RuleGroupType, parentId: string): void;
onGroupRemove(groupId: string, parentId: string): void;
onPropChange(prop: string, value: any, ruleId: string): void;
onRuleAdd(rule: RuleType, parentId: string): void;
onRuleRemove(id: string, parentId: string): void;
showCombinatorsBetweenRules: boolean;
showNotToggle: boolean;
}
getOperators
(Optional)
(field: string) => { name: string; label: string; }[] | null
This is a callback function invoked to get the list of allowed operators for the given field. If null
is returned, the default operators are used.
getValueEditorType
(Optional)
(field: string, operator: string) => 'text' | 'select' | 'checkbox' | 'radio' | null
This is a callback function invoked to get the type of ValueEditor
for the given field and operator. Allowed values are "text"
(the default if the function is not provided or if null
is returned), "select"
, "checkbox"
, and "radio"
.
getInputType
(Optional)
(field: string, operator: string) => string
This is a callback function invoked to get the type
of <input />
for the given field and operator (only applicable when getValueEditorType
returns "text"
or a falsy value). If no function is provided, "text"
is used as the default.
getValues
(Optional)
(field: string, operator: string) => { name: string; label: string; }[]
This is a callback function invoked to get the list of allowed values for the given field and operator (only applicable when getValueEditorType
returns "select"
or "radio"
). If no function is provided, an empty array is used as the default.
getDefaultField
(Optional)
string | ((fieldsData: Field[]) => string)
The default field for new rules. This can be a string identifying the default field, or a function that returns a field name.
getDefaultValue
(Optional)
(rule: Rule) => any
This function returns the default value for new rules.
onQueryChange
(Optional)
(queryJSON: RuleGroup) => void
This is a notification that is invoked anytime the query configuration changes. The query is provided as a JSON structure, as shown below:
{
"combinator": "and",
"not": false,
"rules": [
{
"field": "firstName",
"operator": "null",
"value": ""
},
{
"field": "lastName",
"operator": "null",
"value": ""
},
{
"combinator": "and",
"rules": [
{
"field": "age",
"operator": ">",
"value": "30"
}
]
}
]
}
controlClassnames
(Optional)
This can be used to assign specific CSS
classes to various controls that are created by the <QueryBuilder />
. This is an object with the following signature:
interface Classnames {
queryBuilder: string;
ruleGroup: string;
header: string;
combinators: string;
addRule: string;
addGroup: string;
removeGroup: string;
notToggle: string;
rule: string;
fields: string;
operators: string;
value: string;
removeRule: string;
}
translations
(Optional)
This can be used to override translatable texts applied to various controls that are created by the <QueryBuilder />
. This is an object with the following properties:
{
fields: {
title: "Fields",
},
operators: {
title: "Operators",
},
value: {
title: "Value",
},
removeRule: {
label: "x",
title: "Remove rule",
},
removeGroup: {
label: "x",
title: "Remove group",
},
addRule: {
label: "+Rule",
title: "Add rule",
},
addGroup: {
label: "+Group",
title: "Add group",
},
combinators: {
title: "Combinators",
},
notToggle: {
title: "Invert this group",
}
}
showCombinatorsBetweenRules
(Optional)
boolean
Pass true
to show the combinators (and/or) between rules and rule groups instead of at the top of rule groups. This can make some queries easier to understand as it encourages a more natural style of reading.
showNotToggle
(Optional)
boolean
Pass true
to show the "Not" toggle switch for each rule group.
resetOnFieldChange
(Optional)
boolean
Pass false
not to reset operator and value for field change.
resetOnOperatorChange
(Optional)
boolean
Pass true
to reset value on operator change.
formatQuery
formatQuery
formats a given query in either SQL, parameterized SQL, JSON, or JSON without IDs (which can be useful if you need to serialize the rules). Example:
import { formatQuery } from 'react-querybuilder';
const query = {
id: 'g-b6SQ6WCcup8e37xhydwHE',
rules: [
{
id: 'r-zITQOjVEWlsU1fncraSNn',
field: 'firstName',
value: 'Steve',
operator: '='
},
{
id: 'r-zVx7ARNak3TCZNFHkwMG2',
field: 'lastName',
value: 'Vai',
operator: '='
}
],
combinator: 'and',
not: false
};
console.log(formatQuery(query, 'sql'));
console.log(formatQuery(query, 'parameterized'));
An options
object can be passed as the second argument instead of a format string in order to have more detailed control over the output. The options object takes the following form:
interface FormatQueryOptions {
format?: 'sql' | 'json' | 'json_without_ids' | 'parameterized';
valueProcessor?: (field: string, operator: string, value: any) => string;
quoteFieldNamesWith?: string;
}
For example, if you need to control the way the value portion of the output is processed, you can specify a custom valueProcessor
(only applicable for format: "sql"
).
const query = {
id: 'g-J5GsbcFmZ6xOJCLPPKIfE',
rules: [
{
id: 'r-KneYcwIPPHDGSogtKhG4g',
field: 'instrument',
value: ['Guitar', 'Vocals'],
operator: 'in'
},
{
id: 'r-wz6AkZbzSyDYbPk1AxgvO',
field: 'lastName',
value: 'Vai',
operator: '='
}
],
combinator: 'and',
not: false
};
const valueProcessor = (field, operator, value) => {
if (operator === 'in') {
return `(${value.map((v) => `"${v.trim()}"`).join(',')})`;
} else {
return `"${value}"`;
}
};
console.log(formatQuery(query, { format: 'sql', valueProcessor }));
The 'json_without_ids' format will return the same query without the IDs. This can be useful, for example, if you need to save the query to the URL so that it becomes bookmarkable:
const query = {
id: 'g-J5GsbcFmZ6xOJCLPPKIfE',
rules: [
{
id: 'r-KneYcwIPPHDGSogtKhG4g',
field: 'instrument',
value: ['Guitar', 'Vocals'],
operator: 'in'
},
{
id: 'r-wz6AkZbzSyDYbPk1AxgvO',
field: 'lastName',
value: 'Vai',
operator: '='
}
],
combinator: 'and',
not: false
};
console.log(formatQuery(query, 'json_without_ids'));
IE11 Support
In order to use this library with IE11, you must copy the Microsoft-prefixed crypto
implementation to window.crypto
:
if (!window.crypto) {
window.crypto = window.msCrypto
}
This requirement is due to the inclusion of the nanoid
library.
Development
Changelog Generation
We are using github-changes to generate the changelog.
To use it:
- tag your commit using semantic versioning
- run
npm run generate-changelog
- enter your github credentials at the prompt
- commit
- push your commit and tags
Credits
This component was inspired by prior work from:
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!