ComponentsQuery Builder

QueryBuilder

This component allows you to create conditions and group them using logical operators. It outputs a structured set of rules which can be easily parsed to create SQL/NoSQL/whatever queries.

Take a look at the usage page to learn more about this component.

GitHub LogoSource Code

How to use

The query builder component enables you to create conditions and then group them using logical operators to create structured sets of rules. The output of this component can be easily parsed to create SQL, NoSQL, or any other type of query depending on your use case.

Attributes

To use this component, you’ll need to define your attributes using the attributes property. This property receives an object with all the attributes you’ll be able to choose from to create conditions in the query builder.

An attribute has the following specification:

interface HvQueryBuilderAttribute {
  id?: string;
  label: string;
  type: "boolean" | "numeric" | "dateandtime" | "text" | "textarea" | string;
}

The depth of the query, i.e. the number of nested query groups, can be controlled through the maxDepth where the default value is 1. Furthermore, confirmation dialogs will always be shown by default when removing a condition or group. To change this behavior, the disableConfirmation property is available. If you need your QueryBuilder to be read-only, you can set the readOnly property to true.


No conditions created yet
or a

The query builder already has 5 built-in attribute types, boolean, numeric, text, textarea, and dateandtime, but custom ones can be created if needed.

Find below an example for the attributes property using custom and built-in attribute types.

const attributes: HvQueryBuilderProps["attributes"] = {
  attr1: {
    label: "Numeric",
    type: "numeric",
  },
  attr2: {
    label: "Text",
    type: "text",
  },
  attr3: {
    label: "Text Area",
    type: "textarea",
  },
  attr4: {
    label: "Boolean",
    type: "boolean",
  },
  attr5: {
    label: "Date & Time",
    type: "dateandtime",
  },
  attr6: {
    label: "Custom",
    type: "custom",
  },
};

Combinators

The query builder already has 2 default combinator operands used out of the box: or and and. This set of combinators enables you to define how your conditions can be combined together.

If you want to override the default combinators and define new ones, you can use the combinators property that receives an array of combinators where each combinator has the following specification:

interface HvQueryBuilderQueryCombinator {
  operand: string;
  label: string;
}

Find an example of combinators below.

const combinators: HvQueryBuilderProps["combinators"] = [
  { operand: "or", label: "OR" },
  { operand: "and", label: "AND" },
];

Operators

After defining your attributes, you’ll need to specify the operators for each one of your attribute types through the operators property. This property enables you to define the conditions’ operators by attribute type and combinator.

The query builder already has default operators for each built-in attribute type and they are used out of the box. The default operators are available through the hvQueryBuilderDefaultOperators object exported by UI Kit’s core package. However, you’ll most likely need to override these operators depending on your use case.

An operator has the following specification:

interface HvQueryBuilderQueryOperator {
  operator: string;
  label: string;
  combinators: string[];
}

Find below an example for the operators property.

const operators: HvQueryBuilderProps["operators"] = {
  // Using the default operators for the "boolean", "numeric", "text", "textarea", and "dateandtime" attribute types
  ...hvQueryBuilderDefaultOperators,
  // Defining the operators for the "custom" attribute type
  custom: [
    {
      operator: "equalsTo",
      label: "Equal to (=)",
      combinators: ["and", "or"],
    },
    {
      operator: "notEqual",
      label: "Not equal to (!=)",
      combinators: ["and", "or"],
    },
    {
      operator: "Empty",
      label: "Empty",
      combinators: ["and", "or"],
    },
  ],
};

Initial query

you can pass an initial query to the query builder using the defaultValue property. Use the disableConfirmation property to disable the confirmation dialogs.

Renderers

Having attributes, operators, and combinators enables you to have a fully functional query builder since this component already has some intrinsic behavior.

For instance, the query builder already has built-in value renderers, i.e. inputs to type the condition’s value, for the default attribute types boolean, numeric, text, textarea, and dateandtime. For custom attribute types, a basic text input is rendered by default. Moreover, if the range operator is selected, the condition’s value is cleared automatically, and the value renderer updates to range inputs for the numeric and dateandtime attribute types.

This component also has a default behavior for the Empty and IsNotEmpty operators. When they are selected, the condition’s value is cleared and an empty component is rendered for the value. This behavior is configured through the emptyRenderer property, which enables you to define the operators that should reset the condition’s value and render an empty component when selected.

If you don’t want to rely on the default behavior provided by the query builder and the built-in value renderers are not enough to cover your use case, it’s possible to customize them through the renderers property. This property enables you to customize the value renderers for specific operators and attribute types.

When customizing the query builder, you should note that emptyRenderer takes priority over renderers.

Find below an example on how to customize the value renderers through the renderers property.

const renderers: HvQueryBuilderProps["renderers"] = {
  // Renderer for the custom attribute type "custom"
  custom: CustomRenderer,
 
  text: {
    // Renderer to customize the "Contains" operator of the "text" attribute type
    Contains: ContainsRenderer,
  },
 
  numeric: {
    // Renderer to customize the "numeric" attribute type
    DEFAULT: NumericRenderer,
    // Renderer to customize the "range" operator of the "numeric" attribute type
    range: RangeRenderer,
  },
};

In the example above, 4 renderers were provided:

  • CustomRenderer will be used to render the value for the custom attribute type overriding the default text input used for custom attribute types.
  • ContainsRenderer will be used to render the value for the text attribute type when the Contains operator is selected overriding the default for this operator. When any other operator is selected for this attribute, the query builder relies on its default behavior.
  • NumericRenderer will be used to render the value for the numeric attribute type overriding the default renderer for this attribute type.
  • RangeRenderer will be used to render the value for the numeric attribute type when the range operator is selected. This renderer takes precedence over NumericRenderer when overriding the default renderer.

If necessary, it’s also possible to define value renderers at a more broad level using the DEFAULT key at the root of the renderers object like shown below. You should be aware that DEFAULT is a reserved key, you shouldn’t use to define your own attribute or operator types.

// Example 1
const renderers: HvQueryBuilderProps["renderers"] = {
  // Renderer to customize all attribute types and operators
  DEFAULT: DefaultRenderer,
};
 
// Example 2
const renderers: HvQueryBuilderProps["renderers"] = {
  DEFAULT: {
    // Renderer to customize all attribute types and operators
    DEFAULT: DefaultRenderer,
    // Renderer to customize the "range" operator of all attribute types
    range: DefaultRangeRenderer,
  },
};

In the first example, the DefaultRenderer will be used to render the value for all attribute types and operators. However, in the second example, the DefaultRenderer is used for all attribute types and operators except the range operator since the DefaultRangeRenderer will be used. These customizations have the lowest priority meaning that any renderer defined at the attribute type level will take precedence.

Find below an example where the priorities are annotated.

const renderers: HvQueryBuilderProps["renderers"] = {
  DEFAULT: {
    DEFAULT: DefaultRenderer, // 4
    range: DefaultRangeRenderer, // 3
  },
 
  numeric: {
    DEFAULT: NumericRenderer, // 2
    range: RangeRenderer, // 1
  },
};

Defining renderers

The value renderers are function components that receive the following properties:

interface HvQueryBuilderRendererProps<V = any> {
  id: React.Key;
  attribute: string;
  operator?: string;
  value?: V;
}

Find below an example of a value renderer.

const Renderer = ({ id }: HvQueryBuilderRendererProps) => {
  const { dispatchAction } = useQueryBuilderContext();
 
  return (
    <HvSlider
      required
      label="Slider"
      onChange={(value) => {
        dispatchAction({
          type: "set-value",
          id,
          value,
        });
      }}
    />
  );
};

Custom Renderers example

If the default attribute types (boolean, numeric, text, textarea, and dateandtime) are not enough to cover your use case, custom ones can be used. For these custom types, if no corresponding renderer is provided through the renderers property, a text input will be rendered. The renderers property can also be used to customize the value renderers for specific operators of an attribute type.

dispatchAction is needed to update the query and can be accessed through the useQueryBuilderContext hook exported by the core package. This utility can be used to dispatch several action types such as: reset-query, reset-group, add-rule, add-group, remove-node, set-combinator, set-attribute, set-operator, and set-value. However, you’ll most likely only need the set-value action that enables you to set the value of a condition. This action has the following specification:

{
  type: "set-value";
  id: React.Key;
  value: any;
}

Controlled

The query builder state can be controlled using the value and onChange properties.