@react-querybuilder/chakra
Official react-querybuilder components for Chakra UI.
To see them in action, check out the react-querybuilder
demo or load the example in CodeSandbox.
Full documentation
Installation
npm i react-querybuilder @react-querybuilder/chakra @chakra-ui/icons @chakra-ui/react @chakra-ui/system @emotion/react @emotion/styled framer-motion
Usage
To render Chakra-compatible components in the query builder, wrap the <QueryBuilder />
element in <QueryBuilderChakra />
.
import { ChakraProvider, extendTheme } from '@chakra-ui/react';
import { QueryBuilderChakra } from '@react-querybuilder/chakra';
import { QueryBuilder, RuleGroupType } from 'react-querybuilder';
const chakraTheme = extendTheme();
const fields = [
{ name: 'firstName', label: 'First Name' },
{ name: 'lastName', label: 'Last Name' },
];
const App = () => {
const [query, setQuery] = useState<RuleGroupType>({ combinator: 'and', rules: [] });
return (
<ChakraProvider theme={chakraTheme}>
<QueryBuilderChakra>
<QueryBuilder fields={fields} query={query} onQueryChange={setQuery} />
</QueryBuilderChakra>
</ChakraProvider>
);
};
Notes
-
Some additional styling may be necessary, e.g.:
.queryBuilder .chakra-select__wrapper {
width: fit-content;
display: inline-block;
}
.queryBuilder .chakra-input {
width: auto;
display: inline-block;
}
.queryBuilder .chakra-radio-group {
display: inline-block;
}
-
This package exports chakraControlElements
which can be assigned directly to the controlElements
prop on <QueryBuilder />
(and also exports each component individually), but this method does not support customized Chakra themes like <QueryBuilderChakra />
.
[v7.0.0] - 2024-03-06
Changed
- The minimum React version is now 18, due to the new
react-redux
v9 dependency. - [#654] The minimum TypeScript version is now 5.1.
- [#595] The parser functions have been removed from the main export, and are only available as separate exports. This change reduces the main bundle size by roughly 50%.
<!-- prettier-ignore -->
| Function | New
import
requirement |
| ---------------- | -------------------------------------------------------------------- |
| parseCEL
| import { parseCEL } from "react-querybuilder/parseCEL"
|
| parseJsonLogic
| import { parseJsonLogic } from "react-querybuilder/parseJsonLogic"
|
| parseMongoDB
| import { parseMongoDB } from "react-querybuilder/parseMongoDB"
|
| parseSQL
| import { parseSQL } from "react-querybuilder/parseSQL"
| - [#537] Some of the default labels have been updated per the table below.
<!-- prettier-ignore -->
| Key | Old | New | Notes |
| -------------------------------- | ---------- | ----------- | ----------------------------------- |
|
translations.addRule.label
| "+Rule"
| "+ Rule"
| Space added between "+" and "Rule" |
| translations.addGroup.label
| "+Group"
| "+ Group"
| Space added between "+" and "Group" |
| translations.removeRule.label
| "x"
| "⨯"
| HTML entity ✗
/ ⨯
|
| translations.removeGroup.label
| "x"
| "⨯"
| HTML entity ✗
/ ⨯
| - [#589] The
independentCombinators
prop has been deprecated and will be ignored if used. To enable the independent combinators functionality, use RuleGroupTypeIC
for the query
or defaultQuery
prop. The query builder will detect the query type and behave accordingly. If the independentCombinators
prop is present, a warning will be logged to the console (in "development" mode only). - [#523]
parseMongoDB
now generates more concise queries when it encounters $not
operators that specify a single, boolean condition. Whereas previously that would yield a group with not: true
, it will now generate a rule with a inverted/negated operator ("="
inverted is "!="
, "contains"
inverted is "doesNotContain"
, etc.). To prevent this behavior, set the preventOperatorNegation
option to true
([#653]). - [#589] The
disabled
prop has been un-deprecated. Disabling the entire query with the prop and setting disabled: true
as a property of the root group now produce different behaviors. Specifically, the root group's lock/unlock button will always be enabled if the disabled
prop is not true
. - [#555] Value editors for compatibility packages that render components specific to their respective library now accept an
extraProps
prop that will be passed directly to the library component, spread like {...extraProps}
. The type of extraProps
is any
because each value editor can render one of several library components that accept different props. - [#637] The
"json_without_ids"
export format now explicitly removes the id
and path
properties from the output, leaving all other properties unchanged. Previously this format would only include specific properties which had the effect of removing any non-standard properties. - The first generic argument of
ValueEditorProps
, ValueSelectorProps
, and FieldSelectorProps
must extend the new FullOption
interface instead of Option
.
<details>
<summary>Compatibility packages</summary>
- [#537] Several compatibility packages now override the default labels for non-text components (
lock*
, clone*
, remove*
, and dragHandle
) with SVGs from official icon packages. This brings them more in line with their respective design systems by default.
@react-querybuilder/antd
: @ant-design/icons
@react-querybuilder/bootstrap
: bootstrap-icons
@react-querybuilder/chakra
: @chakra-ui/icons
@react-querybuilder/fluent
: @fluentui/react-icons-mdl2
@react-querybuilder/material
: @mui/icons-material
- [#537]
@react-querybuilder/mantine
now requires Mantine v7. - [#537]
@react-querybuilder/bootstrap
component BootstrapDragHandle
has been removed. It is redundant since dragHandle.label
can now be a ReactNode
.
</details>
<details>
<summary>Low-impact changes</summary>
- [#537] The
useQueryBuilder
hook has been split into useQueryBuilderSetup
and useQueryBuilderSchema
. Each hook takes the full QueryBuilder
props object as its first parameter (as useQueryBuilder
did), and useQueryBuilderSchema
accepts the return value of useQueryBuilderSetup
as its second parameter. - [#537] The
useStopEventPropagation
hook now takes a single function as its parameter instead of an object map of functions, so it must be run for each wrapped function individually. - [#537] Paths are now declared with a new type alias
Path
instead of number[]
. The actual type is the same: type Path = number[]
. - [#537] The
RuleGroupTypeIC
type now includes combinator?: undefined
to ensure that query objects intended for use in query builders where independentCombinators
is enabled do not contain combinator
properties. - [#663] Whereever the native
parseFloat
was used internally, parseNumber
is now used. parseNumber
now delegates parsing to the more versatile numeric-quantity
package. The default behavior has not changed, but a new "enhanced" option will ignore trailing invalid characters (e.g., "abc" in "123abc") just like the native parseFloat
method, with the only difference being it won't return NaN
when parsing fails. Additionally, the numericRegex
export is now adapted from (but largely identical to) the export of the same name from numeric-quantity
. - The logic to prefer a field's
valueEditorType
over the getValueEditorType
prop has moved from the useRule
hook to the useQueryBuilderSetup
hook.
</details>
Added
- Default structural styles (flex direction, alignment, spacing, etc.) are now available in a standalone stylesheet
query-builder-layout.css
/query-builder-layout.scss
. The default stylesheet, query-builder.css
/query-builder.scss
, still contains structural styles but also includes more decorative styles like colors and border styles. The effective styles of the default stylesheet have not changed from version 6. - [#586] Options in list-type props can now use
value
as the identifier property in lieu of name
. Additionally, all Option
s within OptionList
s passed down to subcomponents (fields
, fieldData
, combinators
, operators
, values
, etc.) are guaranteed to have both name
and value
. This makes it easier to use libraries like react-select
that expect a list of type { value: string; label: string; }[]
and not { name: string; label: string; }[]
.
- [#654] Relatedly, field identifier types (
name
/value
properties) will now be inferred from the fields
prop if they have been narrowed from string
. These narrowed types will be applied to subcomponents and other props that take fields or field identifiers as arguments/props. - [#663] The
Field
, Operator
, and Combinator
interfaces each have corresponding Full*
and *ByValue
counterparts. Both name
and value
are required in the Full*
interfaces; only value
is required in the *ByValue
interfaces.
- [#595] Two "bulk override" properties have been added to the
controlElements
prop: actionElement
and valueSelector
. When actionElement
is defined, it will be used for each component that defaults to ActionElement
(as long as that component is not explicitly overridden in the controlElements
prop). Same for valueSelector
and components that default to ValueSelector
(including ValueEditor
in cases where it renders a value selector). This makes it possible to define replacement components for all buttons and selectors at once instead of one-by-one.
<!-- prettier-ignore -->
| controlElements
property | Sets default for |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| valueSelector
| combinatorSelector
, fieldSelector
, operatorSelector
, valueSourceSelector
, valueEditor
(when rendering a value selector) |
| actionElement
| addGroupAction
, addRuleAction
, cloneGroupAction
, cloneRuleAction
, lockGroupAction
, lockRuleAction
, removeGroupAction
, removeRuleAction
| - [#577] A new
showShiftActions
prop provides first-class support for rearranging rules within a query without enabling drag-and-drop. When showShiftActions
is true
, two buttons will appear at the front of each rule and group (except the root group), stacked vertically by default. The first/upper button will shift the rule or group one spot higher, while the second/lower button will shift it one spot lower. Pressing the modifier key (Alt
on Windows/Linux, Option
/⌥
on Mac) while clicking a shift action will clone the rule or group instead of just moving it. A ShiftActions
component has been added, along with a corresponding component for each compatibility package. New translations
properties shiftActionUp
and shiftActionDown
allow configuration of the label and title of each button within the new component. - [#512] Accessibility is improved with the addition of a
title
attribute to the outermost <div>
of each rule group. The text of this attribute can be customized with the accessibleDescriptionGenerator
function prop. - [#537]/[#589] Three new methods make it easier to manage arbitrary query updates from custom components. (Previously we recommended including the query object as a property of the
context
prop, but that workaround is no longer necessary.) The first two methods are available from the schema
prop passed to every component, and should only be used in event handlers. The third is a React Hook and should follow the appropriate rules.
getQuery()
: returns the current root query object.dispatchQuery(query)
: updates the internal query state and then calls the onQueryChange
callback.useQueryBuilderSelector(selector)
: returns the current root query object using the provided selector function, which can be generated with getQuerySelectorById(props.schema.qbId)
.
- Most of the
get*
callback props now receive an additional "meta" parameter with a fieldData
property (more properties may be added to the "meta" object in the future). fieldData
is the full Field
object from the fields
array for the given field
name, including any custom properties (a common one is datatype
). This eliminates the need to find the field object based solely on the field's name
within the get*
functions themselves. The following callback props provide the new "meta" parameter: getDefaultOperator
, getDefaultValue
, getInputType
, getOperators
, getRuleClassname
, getValueEditorSeparator
, getValueEditorType
, getValues
, and getValueSources
. - [#537]
<QueryBuilderDnD />
and <QueryBuilderDndWithoutProvider />
from @react-querybuilder/dnd
now accept a canDrop
callback prop. If provided, the function will be called when dragging a rule or group. The only parameter will be an object containing dragging
and hovering
properties, representing the rule/group being dragged and the rule/group over which it is hovered, respectively. The objects will also contain the path
of each item. If canDrop
returns false
, dropping the item at its current position will have no effect on the query. Otherwise the normal drag-and-drop rules will apply. - [#537] All
label
props and translations.*.label
properties now accept ReactNode
. This includes all action elements (buttons), "not" toggles, and drag handles. Previously label
was limited to string
. This enables, for example, the assignment of SVG elements as labels. - [#537] The
translations
prop can now be passed down through the compatibility context providers like <QueryBuilderBootstrap />
and <QueryBuilderMaterial />
. The object will be merged with the translations
prop of descendant QueryBuilder
components. - [#589] Custom rule processors for
formatQuery
now receive the full Field
object in the options parameter, as long as the fields
array is provided alongside ruleProcessor
. In TypeScript, the member type of the fields
array now requires a label: string
property. Previously, only name
was required. - [#595]
parseMongoDB
now supports custom operators through the additionalOperators
option. - [#589] New utility function
uniqByIdentifier
replaces uniqByName
, which has been deprecated. uniqByIdentifier
will remove duplicates based on the value
property, or name
if value
is undefined (see [#586]). - [#526] Experimental support for ElasticSearch export format in
formatQuery
. - [#606] New compatibility package for Tremor,
@react-querybuilder/tremor
. - [#537] New API documentation, generated directly from the source code, at https://react-querybuilder.js.org/api. In support of this, many types and functions now have better JSDoc comments which should provide a better developer experience in modern IDEs.
- [#638] Value selectors now respect the
disabled
property of individual options in option lists. - [#663] The
format
option set during a call to formatQuery
will be passed to custom rule processors as a property of the options object in the second parameter. - [#663]
parseSpEL
method for importing SpEL expressions.
Fixed
- [#537] Performance is improved (especially for large queries), as long as each prop except for
query
has a stable reference. The most common violation of that rule is probably inline arrow function declarations in the onQueryChange
prop, a problem which can usually be addressed with useCallback
. - [#589] Fixed issue where locking the root group would prevent unlocking the query.
- [#595]
MantineValueSelector
now correctly renders option group headers. - [#619] The package.json#types location has been corrected for all packages. This (probably) only affected legacy build systems that don't support/respect package.json#exports.
- [#623] Fixed an issue where Next triggered the "uncontrolled to controlled" warning unnecessarily. Removed a
useEffect
call from usePrevious
and a ref that tracked "first render" from useQueryBuilderSchema
. - [#625] A default value will not be selected unnecessarily when
valueEditorType
evaluates to "multiselect"
. - Refactored custom hooks to avoid unnecessary
useEffect
calls. - [#663]
formatQuery
for "jsonlogic" will no longer collapse subgroups that only contain one rule into a single JsonLogic rule. Full query objects that contain only one rule will still be collapsed. - [#663] When a
values
list is defined for a field, and the value is reset due to resetOnFieldChange
or resetOnOperatorChange
being true
, the rule value
will no longer be set to the first value in the list unless the valueEditorType
evaluates to "select" or "radio". - [#663]
formatQuery
now renders the fallback expression for subgroups where all rules are invalid. Previously this could result in "()"
, which is invalid SQL.