Skip to content

asafdl/react-conditional-ui

Repository files navigation

CI Release npm Coverage React License: MIT

react-conditional-ui logo
React component library for "type to build" conditions via natural language input, fast and lightweight, no LLM required! Users type plain-English phrases (e.g. "status is active") instead of filling out combo boxes. A fuzzy parser resolves fields, operators, and values, with support for compound `AND`/`OR` conditions that transform into interactive drag-and-drop condition groups.

Live Demo

Components

<ConditionalUI />

All-in-one component: input field + parsed condition output with editing and drag-and-drop.

import { ConditionalUI } from "react-conditional-ui";

<ConditionalUI
    fields={[
        { label: "Status", value: "status" },
        { label: "Age", value: "age", type: "number" },
    ]}
    onConditionsChange={(groups) => console.log(groups)}
/>;

<Input />

Standalone text input with fuzzy parsing, ghost autocomplete, and inline diagnostics.

import { Input } from "react-conditional-ui";

<Input fields={fields} operators={operators} onSubmit={(group) => console.log(group)} />;

Also supports a fully controlled mode via useConditionalInput:

import { Input, useConditionalInput } from "react-conditional-ui";

const { text, diagnostics, handleChange, handleSubmit, getSuggestion } = useConditionalInput({
    fields,
    onSubmit: handleGroup,
});

<Input
    value={text}
    onChange={handleChange}
    onSubmit={handleSubmit}
    getSuggestion={getSuggestion}
    diagnostics={diagnostics}
/>;

<Output />

Renders parsed condition groups as interactive chip rows with drag-and-drop reordering, chip editing via popovers, connector toggling, and entry removal.

Uncontrolled (manages its own state):

import { Output } from "react-conditional-ui";

<Output fields={fields} operators={operators} />;

Controlled:

<Output groups={groups} fields={fields} operators={operators} onGroupsChange={setGroups} />

Read-only (pass groups without onGroupsChange):

<Output groups={groups} fields={fields} operators={operators} />

Data Model

The <Input /> parser converts free-text into a ConditionGroup which the <Output /> renders. The full type hierarchy:

ConditionGroup
├── id: string
├── config?: GroupConfig
└── entries: ConditionEntry[]
        ├── id: string
        ├── connector: "and" | "or"
        └── condition: ParsedCondition
                ├── field:    { raw, value, label, isValid }
                ├── operator: { raw, value, label, isValid }
                └── value:    { raw, value, label, isValid, errorMessage?, matchedOption? }

For example, typing "status is active and age greater than 18" produces:

{
  "id": "g1",
  "entries": [
    {
      "id": "e1",
      "connector": "and",
      "condition": {
        "field":    { "raw": "status",       "value": "status", "label": "Status",       "isValid": true },
        "operator": { "raw": "is",           "value": "is",     "label": "is",           "isValid": true },
        "value":    { "raw": "active",       "value": "active", "label": "active",       "isValid": true }
      }
    },
    {
      "id": "e2",
      "connector": "and",
      "condition": {
        "field":    { "raw": "age",          "value": "age",    "label": "Age",          "isValid": true },
        "operator": { "raw": "greater than", "value": "gt",     "label": "greater than", "isValid": true },
        "value":    { "raw": "18",           "value": "18",     "label": "18",           "isValid": true }
      }
    }
  ]
}

This is the same object surfaced by onConditionsChange (as an array of groups), onSubmit on the <Input />, and useConditionalOutput's groups state.

Customization

Use these when you want to keep parser behavior but tailor UI/interaction details.

Component-level options

  • <ConditionalUI />: pass InputComponent and/or OutputComponent to replace either half of the default UI.
  • <Input />: customize placeholder, className, and style.
  • <Output />: customize defaultGroupConfig, className, and style.
  • All components support controlled patterns (value/onChange, groups/onGroupsChange) where applicable.
<ConditionalUI
    fields={fields}
    InputComponent={MyInput}
    OutputComponent={MyOutput}
    onConditionsChange={setGroups}
/>

Field-level parser options

FieldOption supports per-field parsing behavior:

  • operators: override allowed operators for a specific field
  • fieldValues: provide known values (useful for enum-like suggestions)
  • type: built-in value checks ("text" | "number" | "enum")
  • validateValue: custom validator (true or error string)

Group configuration

Each ConditionGroup can define config:

const group: ConditionGroup = {
    id: "1",
    entries: [...],
    config: {
        editable: false,
        removable: false,
        variant: "filled", // "outlined" (default) or "filled"
        label: "Filters",
    },
};

Set defaults for all groups with defaultGroupConfig on <Output />.

Hooks for custom UI

Use hooks when you want your own input/output rendering and state wiring.

useConditionDataProvider

Lowest-level API: returns parseComplexCondition, getSuggestion, getCompletions, diagnose, and provider. Use it when you already control input state and submit flow.

import { useConditionDataProvider, DEFAULT_OPERATORS } from "react-conditional-ui";

const { parseComplexCondition, getSuggestion, diagnose } = useConditionDataProvider({
    fields,
    operators: DEFAULT_OPERATORS,
});

const group = parseComplexCondition(raw);
const issues = diagnose(raw);

useConditionalInput

Input-state helper for controlled/uncontrolled text, submit validation, and diagnostics.

useConditionalOutput

Group-state + mutations without rendering <Output />; use this to build your own chips/list/table UI.

Includes helpers like addGroup, removeEntry, toggleConnector, updateCondition, updateGroupConfig, reordering/move helpers, and setGroups.

import { useConditionalOutput } from "react-conditional-ui";

const { groups, mutations } = useConditionalOutput({
    onGroupsChange: (groups) => console.log(groups),
});

mutations.addGroup(parsedGroup);

Styling

All components accept className and style props. Internal elements use rcui-* CSS classes that can be overridden.

Error handling

  • Parsing/validation issues are exposed as Diagnostic[] (start, end, message) via useConditionalInput and controlled <Input /> mode.
  • Managed input submit is fail-safe: invalid conditions are not emitted via onSubmit; diagnostics are shown instead.
  • Use useConditionDataProvider().diagnose(text) when building custom UIs and FieldOption.validateValue for field-specific validation rules.

Debug logging

The library uses the debug package. Logs are silent by default. Enable them to see how the fuzzy parser resolves fields, operators, and values:

// Browser — enable all library logs
localStorage.debug = "react-conditional-ui:*";

// Browser — specific namespace only
localStorage.debug = "react-conditional-ui:parser";
# Node / SSR
DEBUG=react-conditional-ui:* node app.js

Available namespaces: parser, match-engine.

Local development

npm install
npm run dev
npm run build
npm test
npm run lint
npm run format

About

React Component for building conditions via natural language input.

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors