🔔 Alert..!! Get 2 Month Free Cloud Hosting With $200 Bonus From Digital Ocean ACTIVATE DEAL

A configurable, user-friendly React component to build queries.

Others React

Documentation

react-awesome-query-builder

User-friendly React component to build queries.

Forked from https://github.com/fubhy/react-query-builder

Inspired by jQuery QueryBuilder

Using awesome Ant Design for widgets

Master branch uses antd v2 (because of more compact style) and versions 0.1.*. For antd v3 see branch antd-3 and versions 0.2.*.

Features

  • Highly configurable
  • Fields can be of type:
    • simple (string, number, bool, date/time/datetime, list)
    • structs (will be displayed in selectbox as tree of members)
    • custom type (dev should add its own widget component for this) (it's not complex, you can add slider for example)
  • Comparison operators can be:
    • binary (== != < > ..)
    • unary (is empty, is null)
    • 'between' (for numbers)
    • complex operators like 'proximity'
  • Values of fields can be compared with values -or- another fields (of same type)
  • Reordering support for rules and groups of rules
  • Using awesome Ant Design
  • Export to MongoDb or SQL

Demo

Live Demo

Screenshot

Install

Install: npm i react-awesome-query-builder

See examples/demo as example of usage and configuration.

For full reordering support you need to add class query-builder-container for dom-element which is holding your querybuilder component AND has scrolling. If there is no such dom-element (only body) you can do nothing.

Use

import React, {Component} from 'react'; import {Query, Builder, Utils as QbUtils} from 'react-awesome-query-builder'; import config from './config'; //see below 'Config format' import 'react-awesome-query-builder/css/styles.scss'; import 'react-awesome-query-builder/css/compact_styles.scss'; import 'react-awesome-query-builder/css/denormalize.scss';  class DemoQueryBuilder extends Component {     render() {                         return (             <div>                 <Query                    {...config}                    //you can pass object here, see treeJSON at onChange                   //value=transit.fromJSON(treeJSON)                   get_children={this.getChildren}                   onChange={this.onChange}                 ></Query>             </div>         );     }          getChildren(props) {         return (             <div>                 <div className="query-builder">                     <Builder {...props} />                 </div>                 <div>Query string: {QbUtils.queryString(props.tree, props.config)}</div>                 <div>Mongodb query: {QbUtils.mongodbFormat(props.tree, props.config)}</div>             </div>         )     }          onChange(tree) {       //here you can save tree object:        //var treeJSON = transit.toJSON(tree)     } }

Use can save tree as serialized Immutable object with transit.toJSON/transit.fromJSON -or- as plain JS, see loadTree = function(serTree) {...} at examples/demo/demo.js (using Immutable.fromJS with a little trick)

Config format

import {Widgets, Operators} from 'react-awesome-query-builder'; const {     TextWidget,     NumberWidget,     SelectWidget,     MultiSelectWidget,     DateWidget,     BooleanWidget,     TimeWidget,     DateTimeWidget,     ValueFieldWidget } = Widgets; import en_US from 'antd/lib/locale-provider/en_US';  export default {   conjunctions: {     'AND': {       label: 'And', //label for conjunctions swicther       //(for building query string) function to join rules into group       // children - list of already formatted queries (strings) to be joined with conjuction       // isForDisplay - false by default, for building query string for SQL/expression/etc.,        //  true can be used to format query string displayed on collapsed query group        //  (not used for now, see Issue #2)       formatConj: (Immultable.List children, string conj, bool not, bool isForDisplay) => string,       reversedConj: 'OR', //'AND' reverses to 'OR'       //for building mongodb query:       mongoConj: '$and',     },     'OR': ...same as for 'AND'   },      fields: {     //Example of atomic field:     name: {       label: 'Quantity',       type: 'number', //one of types described below in section 'types'       //Settings for widgets       // Available settings for Number widget: min, max, step       fieldSettings: {           min: 2,       },       //List of values for Select widget       listValues: {         //<key>: <label to display at list of options>,         yellow: 'Yellow',         green: 'Green',       },       //(optional) You can override here some options of config of corresponding type:       // 'operators', 'defaultOperator', 'widgets', 'valueSources' (see below at section 'types')     },     //Example of special struct field:     members: { //key of field       label: 'Members', //label to display at list of fields       type: '!struct', //special type for struct       subfields: { //only for type == '!struct'         subname: { //key of subfield           label: 'Subname', //label for list of fields           //label for field menu's toggler (for config.renderFieldAndOpAsDropdown == true)           label2: 'MemberName',           type: 'text', //one of types described below in section 'types'         },       },     },     ...other fields   },      types: {     number: { //type key       //(optional) Values of fields can be compared with values or another fields       // (see settings.valueSourcesInfo). If you want to compare values of this type        // only with values or other fields of this type, edit:       valueSources: ['value'],       //Available widgets for type and its configs:       widgets: {         number: { //widget key, see section 'widgets' below           //List of operators can be applied to this type (see section 'operators' below)           operators: ['greater', 'less'],           defaultOperator: 'greater', //default operator to be selected for this type           //Config for this widget (all optional):           widgetProps: {             //for example, here you can overwrire 'valueLabel', 'valuePlaceholder',              // for date/time: 'timeFormat', 'dateFormat', 'valueFormat'              //also you can pass props directly to widget, for example enable search for Select widget:             customProps: {                 showSearch: true             }           },           //Config for operators for this widget (all optional):           opProps: {             between: { //operator key               //for example, here you can overwrire 'valueLabels'             },             ...other ops           },         },         //Most of types can have only 1 widget, but for list there can be 2:          // single-select widget (for op ==) and multi-select widget (for op 'in')         ...other widgets if applicable         //'field' is special widget to compare values of field of this type         // with another fields (of this type)         field: {           ...you can overwrire 'operators' for example         }       }     },     ...other types   },      operators: {     equal: { //operator key       label: '==', //label for selectbox       labelForFormat: '==', //string used for formatting query, only if 'formatOp' is not present       reversedOp: 'not_equal', //operator opposite to current       cardinality: 1, //number of right operands (1 for binary, 2 for 'between')       isUnary: true,       //(for building query string) function to format rule       // value - string (already formatted value) for cardinality==1        // -or- Immutable.List of strings for cardinality>1       formatOp: (string field, string op, mixed value, string valueSrc, string valueType,          Object opDef, Object operatorOptions, bool isForDisplay) => string,       //(for building mongodb query) function to format rule       // value - mixed for cardinality==1 -or- Array for cardinality>2        mongoFormatOp: (string field, string op, mixed value) => object,       //for cardinality==2 ('between')       valueLabels: ['Value from', {label: 'Value to', placeholder: 'Enter value to'}],       textSeparators: [null, 'and'],       ...also see examples/demo for config of 'proximity' operator     },   },      widgets: {     text: {       type: "text", //see 'types' section       valueSrc: 'value', //'value' or 'field' (only for special 'field' widget)       factory: (props) => <TextWidget {...props} />, //React component       //(for building query string) function to format widget's value       formatValue: (mixed val, Object fieldDef, Object wgtDef, bool isForDisplay) => string,       //(for building mongodb query) function to convert widget's value       mongoFormatValue: (mixed val, Object fieldDef, Object wgtDef) => object,       //func to validate widget's value       validateValue: (mixed val, Object fieldDef) => bool,       //Options:       // common:       valueLabel: "Text",       valuePlaceholder: "Enter text",       // for date/time widgets:       timeFormat: 'HH:mm',       dateFormat: 'YYYY-MM-DD',       valueFormat: 'YYYY-MM-DD HH:mm',       // ...for your custom widgets you can add here your options       // also you can pass customProps, for example to enable search for select widget:       customProps: { showSearch: true }     },     ...other widgets (you can add your custom ones here)     ...also there should be special 'field' widget, see examples/demo   },      settings: {     //Locale used for AntDesign widgets     locale: {         short: 'en',         full: 'en-US',         antd: en_US,     },     //To shorten long labels of fields/values (by length, i.e. number of chars)     maxLabelsLength: 50,     //Placement of antdesign's dropdown pop-up menu (default: 'bottomLeft')     dropdownPlacement: 'bottomRight',     //Don't show conjunctions switcher for only 1 rule?     hideConjForOne: true,     //Size of AntDesign components     renderSize: 'small',     //How to render conjunctions switcher? true - use RadioGroup, false - use ButtonGroup     renderConjsAsRadios: false,     //How to render fields/ops list? true - use Dropdown/Menu, false - use Select     renderFieldAndOpAsDropdown: false,     //You can pass props to Select field widget     customFieldSelectProps: {         showSearch: true     },     // You can change the position of the group actions to the following:     // oneOf [topLeft, topCenter, topRight (default), bottomLeft, bottomCenter, bottomRight]     groupActionsPosition: 'topRight',      //Strategies for selecting operator for new field (used by order until success)     // 'default' (default if present), 'keep' (keep prev from last field), 'first', 'none'     setOpOnChangeField: ['keep', 'default'],     //Clear value on field change? false - if prev & next fields have same type (widget), keep     clearValueOnChangeField: false,     //Clear value on operator change?     clearValueOnChangeOp: false,     //?     setDefaultFieldAndOp: false,     //Max nesting for rule groups     maxNesting: 10,     //Separaor for struct fields     fieldSeparator: '.', //also used for formatting     fieldSeparatorDisplay: '->', //used for toggler's text for renderFieldAndOpAsDropdown==true     //Show labels under all ui fields?     showLabels: false,     //Show NOT together with AND/OR?     showNot: true,     //Next options are for localization:     valueLabel: "Value",     valuePlaceholder: "Value",     fieldLabel: "Field",     operatorLabel: "Operator",     fieldPlaceholder: "Select field",     operatorPlaceholder: "Select operator",     deleteLabel: null,     addGroupLabel: "Add group",     addRuleLabel: "Add rule",     readonlyMode: false,     notLabel: "Not",     delGroupLabel: null,     valueSourcesPopupTitle: "Select value source",     //Leave empty group after deletion or add 1 clean rule immediately?     canLeaveEmptyGroup: true, //after deletion     //(for building query string) function to format rule with reverse operator      // which haven't 'formatOp'     // q - already formatted rule for opposite operator (which have 'formatOp')     // return smth like "NOT(" + q + ")"     formatReverse: (string q, string operator, string reversedOp, Object operatorDefinition,        Object revOperatorDefinition, bool isForDisplay) => string,     //(for building query string) function to format field     // parts - for struct field     // label2 - with using of 'fieldSeparatorDisplay'     //just return field (or label2 for isForDisplay==true)     formatField: (string field, Array parts, string label2, Object fieldDefinition, Object config,        bool isForDisplay) => string,     //Values of fields can be compared with values or another fields     //If you want to disable this feature and leave only comparing with values, remove 'field'     valueSourcesInfo: {       value: {         label: "Value"       },       field: {         label: "Field",         widget: "field",       }     },     //Activate reordering support for rules and groups of rules?     canReorder: true,     //(For comparing field with field) Function for building right list of fields to compare     canCompareFieldWithField: (string leftField, Object leftFieldConfig, string rightField,        Object rightFieldConfig) => {         //for type == 'select'/'multiselect' you can check listValues         return true;     },   }, } 

Development

To build the component locally, clone this repo then run:

npm install npm run examples

Then open localhost:3001 in a browser.

Scripts:

  • npm run build-npm - Builds a npm module. Output path: build/npm
  • npm run build-global - Builds with webpack the self contained pack of the component. Output path: build/global
  • npm run build-examples - Builds with webpack the examples. Output path: examples
  • npm run examples - Builds with webpack the examples and runs a dev-server on localhost:3001.
  • sh ./scripts/gh-pages.sh - Update gh pages

The repo sticks in general to the Airbnb JavaScript Style Guide.

Pull Requests are always welcomed :)

License

MIT. See also LICENSE.txt


You May Also Like