npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

query-builder-react

v5.12.0

Published

Advanced React query builder that lets users write a query in a free-text input or build it visually from a popover, with column/operator/value rows and AND/OR logic.

Readme

QueryBuilder Component

Overview

The QueryBuilder component helps users build complex search queries using an intuitive UI. It supports nested groups with mixed AND/OR logic, NOT negation, and parenthesized sub-expressions — all through both a free-text input and a visual form builder.


Features

  • Nested Group Builder: Create groups of conditions with independent AND/OR combinators and NOT negation.
  • Mixed AND/OR: Combine AND and OR in a single query using parentheses for grouping.
  • Free-Text Input: Type queries directly with syntax highlighting, autocomplete suggestions, and validation.
  • Visual Form Builder: Build queries visually via a popover with group/rule management.
  • Bidirectional Sync: Changes in the text box reflect in the form, and vice versa.
  • Customizable: Define columns and their valid operators.
  • Theme-Aware: Token colors resolve from the MUI theme palette — works in both light and dark mode out of the box.
  • Fully Styleable: Every visual element can be styled via the sx slot map.
  • Callback Support: Trigger a function with the full query tree when applied.

Installation

Ensure you have Material-UI installed alongside the package:

# with pnpm
pnpm add query-builder-react @mui/material @mui/icons-material @emotion/react @emotion/styled

# or with npm
npm install query-builder-react @mui/material @mui/icons-material @emotion/react @emotion/styled

# or with yarn
yarn add query-builder-react @mui/material @mui/icons-material @emotion/react @emotion/styled

Usage

Basic Example:

import React from "react";
import QueryBuilder from "query-builder-react";

const columnsOperator = {
  name: { operators: ["contains", "exclude", "==", "!="] },
  id: { operators: ["contains", "exclude", "==", "!="] },
  duration: { operators: ["<", "<=", ">", ">=", "==", "!="] },
  created_at: { operators: ["before", "after", "exact"] },
};

export default function App() {
  const handleApply = (groupTree) => {
    console.log("Query tree:", groupTree);
  };
  return (
    <QueryBuilder
      columnsOperator={columnsOperator}
      defaultOperators={["AND", "OR"]}
      relatedOperators={[
        "contains",
        "exclude",
        "!=",
        "==",
        "<",
        "<=",
        ">",
        ">=",
        "before",
        "after",
        "exact",
      ]}
      placeholder='e.g. name contains "John" AND (duration > 30 OR status == active)'
      handleApply={handleApply}
    />
  );
}

Query Syntax

The free-text input supports the following syntax:

<column> <operator> <value> [AND|OR <column> <operator> <value>]...

Parentheses & Mixed Logic

You can mix AND and OR using parentheses to control precedence:

name contains "John" AND (status == active OR status == pending)
Trademark = Audi AND (Cylinders = 4 OR Doors = 2)

Without parentheses, AND binds tighter than OR:

a = 1 OR b = 2 AND c = 3
// is parsed as: a = 1 OR (b = 2 AND c = 3)

NOT Negation

Prefix a group with NOT to negate it:

NOT (status == inactive OR status == deleted)

Query Tree Structure

The handleApply callback receives a recursive group tree:

{
  type: "group",
  combinator: "AND",  // "AND" | "OR"
  not: false,         // true if negated
  rules: [
    { type: "rule", column: "Trademark", operator: "=", value: "Audi" },
    {
      type: "group",
      combinator: "OR",
      not: false,
      rules: [
        { type: "rule", column: "Cylinders", operator: "=", value: "4" },
        { type: "rule", column: "Doors", operator: "=", value: "2" },
      ]
    }
  ]
}

Helper Utilities

The package exports helper functions for working with the tree:

import { flattenGroupToQueries, convertGroupToText } from "query-builder-react/helpers";

// Flatten to a simple array of {column, operator, value}
const flat = flattenGroupToQueries(groupTree);

// Serialize back to a human-readable string
const text = convertGroupToText(groupTree);
// → 'Trademark = Audi AND (Cylinders = 4 OR Doors = 2)'

Visual Query Builder (Form)

The popover form supports:

  • Groups with NOT / AND / OR: Each group has a NOT toggle and an AND/OR combinator selector.
  • Nested sub-groups: Click the circled + button to add a sub-group within any group.
  • Add/delete rules: Use + to add rules, × to remove them.
  • Search/Cancel: Apply the built query or dismiss.

Changes made in the form automatically sync to the text input, and vice versa.


Props

| Prop | Type | Default | Description | | ------------------ | ---------- | ----------- | ------------------------------------------------------------ | | columnsOperator | object | {} | Defines columns and their valid operators. | | defaultOperators | string[] | [] | Logical operators for combining queries (e.g., AND, OR). | | relatedOperators | string[] | [] | List of valid operators for the query builder. | | handleApply | function | undefined | Callback triggered with the group tree when applied. | | placeholder | string | "" | Placeholder text shown inside the query text box when empty. | | sx | object | {} | Style overrides for individual slots. See Custom Styling. |


Custom Styling

The QueryBuilder component is fully styleable from the outside through the sx prop. Instead of accepting a single style object, sx is a slot map: each key targets a specific part of the rendered tree, and its value is any valid MUI sx value.

QueryBuilder Slots

| Slot | Targets | | ------------------- | --------------------------------------------------------------------------------- | | root | The outer wrapper Box of the entire component. | | textBoxContainer | The Box wrapping the QueryTextBox and the tune button. | | textBox | A nested slot map forwarded to QueryTextBox. See Text Box Slots. | | iconButton | The tune (settings) IconButton. | | popover | The advanced-filters Popover (wrapper). | | popoverPaper | The Paper element inside the Popover. Override responsive width / height caps here. | | popoverContent | The inner Box inside the popover. | | title | The "Query Builder" title Typography. | | queryForm | A nested slot map forwarded to QueryForm. See Query Form Slots. |

All slots are optional. Any slot you don't provide simply falls back to the component's default styling.

Text Box Slots

| Slot | Targets | | ------------------- | -------------------------------------------------------------------- | | root | The outer wrapper Box of QueryTextBox. | | inputRow | The Box wrapping the OutlinedInput and the Apply Button. | | inputWrapper | The relative-positioned wrapper that holds the highlight overlay + input. | | highlightOverlay | The transparent Box that paints colored tokens behind the input. | | input | The OutlinedInput field. | | adornmentBox | The flex Box inside the input's end adornment. | | helpButton | The help (?) IconButton. | | helpTooltip | The Tooltip wrapping the help icon. | | applyButton | The Apply Button. | | errorTooltip | The validation-error Tooltip shown for invalid queries. | | hintTooltip | The hint Tooltip shown for an empty input. | | popper | The suggestions Popper. | | suggestionsBox | The Box rendered inside the popper. | | suggestionsList | The List of suggestions. | | suggestionItem | Each ListItemButton inside the suggestions list. | | suggestionText | The Typography displaying each suggestion's text. | | tokenColors | Color overrides for syntax-highlighted tokens. See Token Highlighting. | | tokenFontWeights | Font-weight overrides per token type. See Token Font Weights. | | helpModal | A nested slot map forwarded to the help modal. See Help Modal Slots. |

Token Highlighting

As the user types, QueryTextBox parses the input into typed tokens and paints each one in a distinct color. Colors default to MUI theme palette tokens, so they adapt to light/dark mode automatically. You can override via sx.textBox.tokenColors.

| Token Type | Default Color | When It's Used | | ------------------ | ------------------------ | ------------------------------------------------------------- | | column | primary.main | Token matching a configured column. | | customColumn | info.main | Token at column position that is not in configured columns. | | operator | error.main | Token matching a known operator. | | unknownOperator | text.disabled | Token at operator slot that doesn't match any known operator. | | logical | secondary.main | Logical connectors — AND / OR / NOT. | | paren | warning.main | Parentheses ( and ). | | value | text.primary | The right-hand side value token. |

<QueryBuilder
  sx={{
    textBox: {
      tokenColors: {
        column: "#0d47a1",
        customColumn: "#00897b",
        operator: "#c2185b",
        logical: "#6a1b9a",
        paren: "#e65100",
        value: "#212121",
      },
    },
  }}
/>
Token Font Weights

| Token Type | Default Weight | | ------------------ | ------------------ | | column | 400 | | customColumn | 400 | | operator | 600 | | unknownOperator | 400 | | logical | 600 | | paren | 700 | | value | 400 |

Query Form Slots

The visual query builder form inside the popover exposes its own slot map via sx.queryForm.

| Slot | Targets | | ------------------------ | -------------------------------------------------------------- | | root | The outer wrapper Box of the form. | | columnSelect | The column Select in each rule row. | | operatorSelect | The operator Select in each rule row. | | valueInput | The value TextField in each rule row. | | deleteButton | The delete IconButton for each rule/group. | | actions | The action-buttons row Box (Search + Cancel). | | applyButton | The "Search" Button. | | cancelButton | The "Cancel" Button. |

Help Modal Slots

| Slot | Targets | | ------------------- | -------------------------------------------------------------------- | | dialog | The Dialog itself. | | title | The DialogTitle. | | closeButton | The close (x) IconButton in the title. | | content | The DialogContent. | | sectionTitle | Each section heading inside the content. | | body | Each paragraph Typography inside the content. | | codeBlock | The grey-background code blocks. | | exampleBlock | Each individual example code block. | | exampleLabel | The uppercase caption above each example. | | list | Each <ul> inside the content. | | listItem | Each <li> Typography. | | chip | Each inline Chip. | | divider | Each section Divider. | | colorLegendItem | Each list item in the syntax-highlighting color legend. | | colorSwatch | The colored circle next to each legend item. | | actions | The DialogActions row. | | gotItButton | The "Got it" Button. |

Styling Example

<QueryBuilder
  columnsOperator={columnsOperator}
  defaultOperators={["AND", "OR"]}
  relatedOperators={relatedOperators}
  handleApply={handleApply}
  sx={{
    root: { height: "52px" },
    textBoxContainer: { height: "52px" },
    textBox: {
      tokenColors: {
        value: "#212121",
      },
      input: { height: "52px" },
    },
    popover: {
      "& .MuiPopover-paper": {
        width: { xs: "calc(100vw - 32px)", sm: 520 },
        maxWidth: "calc(100vw - 32px)",
      },
    },
    popoverContent: {
      "& .MuiInputBase-input, & .MuiSelect-select": {
        py: "4px",
        minHeight: "unset",
        fontSize: "12px",
      },
      "& .MuiButton-root": {
        textTransform: "none",
        fontSize: "12px",
      },
    },
  }}
/>

How It Works

  1. Query Text Box: Type queries directly with real-time syntax highlighting and autocomplete. Supports parentheses for grouping and mixed AND/OR.
  2. Popover (Tune Icon): Opens a visual form for building nested rule groups with independent AND/OR combinators and NOT toggles.
  3. Bidirectional Sync: Applying from the text box updates the form, and applying from the form updates the text box.
  4. Apply: The handleApply callback receives the full group tree structure.

Notes

  • Required Props: columnsOperator and handleApply are essential for the component to work effectively.
  • Custom Operators: Add or modify operators in columnsOperator or relatedOperators to suit your needs.
  • Theme Support: Token colors use MUI theme palette tokens by default, so they work correctly in both light and dark mode without additional configuration.

License

MIT