Skip to content

SIG—09 Signature system

QueryBuilder

Conditions that read as a sentence: typed operators per field, nested any/all groups, a plain-language reading and an evaluator for local filtering.

Live — this one is real

Scenario

Illustrative accounts. The table below is filtered live with matchesQuery; the reading comes from describeQuery.

Conditions: match all
Match all or any conditions
  1. seats
  2. Group: match any
    Match all or any conditions in this group
    1. days
    2. Region3 selected
      Region

Reads asPlan is any of Pro, Team, and Seats ≥ 10 seats, and (Signed up is in the last 90 days, or Region is any of Germany, Norway, Japan)

Matching accounts — Plan is any of Pro, Team, and Seats ≥ 10 seats, and (Signed up is in the last 90 days, or Region is any of Germany, Norway, Japan)
Region
Cedar Studiopro17India2026-09-22
Bright Labspro16Japan2026-02-11
Harbor Healthpro10Japan2026-08-13
Harbor Foodspro14Canada2026-08-18
Kite Studioteam12Canada2026-08-31
Signal Studiopro11Norway2026-06-20

Usage

tsx
import { useState } from "react";
import { QueryBuilder, type QueryGroup } from "mizu-ui";

export function Example() {
  const [query, setQuery] = useState<QueryGroup>({
    id: "root",
    combinator: "and",
    rules: [{ id: "a", field: "plan", operator: "is", value: "pro" }],
  });
  return (
    <QueryBuilder
      label="Audience"
      value={query}
      onValueChange={setQuery}
      fields={[
        {
          id: "plan",
          label: "Plan",
          type: "select",
          options: [
            { value: "free", label: "Free" },
            { value: "pro", label: "Pro" },
          ],
        },
        { id: "seats", label: "Seats", type: "number" },
        { id: "joined", label: "Joined", type: "date" },
      ]}
    />
  );
}

This code, running — no configuration beyond the data

Conditions: match all
Match all or any conditions

Reads asPlan is Pro

Source & setup

Add this component to your project with the shadcn CLI. The command copies its source and styles into your configured UI directory.

sh
npx shadcn@latest add 0xuser64bit/mizu/query-builder

For npm imports, import mizu-ui/styles.css once. Fonts are optional via mizu-ui/fonts.css. Override --mizu-* tokens or use className for local styling. Requires React and Motion.

Inspect signature/QueryBuilder.tsx

Source is included in the npm package under src/signature/QueryBuilder.tsx.

Open full source ↗

Props

PropTypeDefaultDescription
label / fieldsstring / QueryField[]—Region name; fields have id, label, type (text, number, date, select, boolean), options and unit.
value / defaultValue / onValueChangeQueryGroup—The query: a combinator and rules or nested groups.
maxDepthnumber3Group nesting limit.
footerReactNode—Beside the reading, e.g. a live match count.
describeQuery(query, fields)function—The plain-language reading, for saved segments.
matchesQuery(query, record, fields, now?)function—Evaluate a record locally; incomplete rules are ignored.

Accessibility

Each group is a fieldset; the all/any choice is a real radio group. Every condition is a named group of native selects and inputs with specific labels, and an incomplete condition is described in words. Additions and removals are announced, and a new condition receives focus.

Motion

New conditions unfold from the left, removed ones close, and the and/or joins roll over like a counter when a group's logic changes. Reduced motion shows each change immediately.

Works alongside