For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt, and this page is available as Markdown at https://wallarm.github.io/design-system/components/filter-input.md.

FilterInput

A config-driven query builder — fields metadata in, an ExprNode tree out of onChange — for filtering a data-dense resource. Reach for a row of Selects instead when three or four facets picked by equality would do; reach for this when the attribute count is high, or the query needs AND/OR, grouping, or operators like between and like. The menus, chips and connectors are internal, so what you own is the field config.

Source · Storybook

Usage

import { FilterInput } from '@wallarm-org/design-system/FilterInput';

Examples

FilterInput

With keyboard hint

showKeyboardHint prints the shortcut hint beside the input — worth turning on where filtering is new to the reader, and off where it is routine.

With field groups

fieldGroups sorts the field menu under labelled headers, which is what keeps a fifty-field schema navigable.

With described chip

A field with a description carries it into a tooltip on the chip's first segment, so a committed filter can still explain itself; the operator and value segments keep click-to-edit.

Error empty

error reddens the input as a whole — pair it with an Alert that says what was rejected, since the input itself cannot.

With preset value

Controlled mode: value takes an ExprNode and onChange hands the tree back. The JSON below the input is the story printing that tree, not part of the component.

With multi condition preset

Two conditions joined by AND — what a group node looks like once rendered, connectors included.

Error with value

The error state with a condition already committed: the chip stays editable, so the query can be fixed in place rather than cleared.

With disabled chips

A condition marked disabled is locked — dimmed, no edit, no remove — which is how a drill-down carries its context into the filter without letting the reader drop it.

All chips disabled

With every chip locked, clear-all has nothing to remove, and the input still accepts new conditions on top.

HTTP status code suggestions

A status-code field wired by hand with the createStatusCode* helpers: typing narrows the mask suggestions, 4 to 4XX and 40 to 40X.

HTTP status code by name

status_code is a reserved field name — the DS fills in the same suggestions, input filter, normaliser and validator on its own, and an explicit callback still wins.

Paired field

pairedField captures two steps in one chip — a parameter name, then its value with its own operator — for an attribute that means nothing on its own.

Paired field value is set

is set and is not set on the paired half finish the chip with no second value, which is how you ask whether a key is present at all.

Paired field value descriptions

The value rows carry a muted second line because the bold name is not unique: two request-id rows differ only by their path, and selecting one commits the path.

Paired field preset

The same paired field arriving pre-filled from a controlled value, rendered as the single chip it becomes.

Nested value submenu

Values grouped under section headers, with one row opening a submenu of sub-types: only leaves commit, so the expression never carries a group. A fully selected group collapses to its own label in the chip while a partial one lists the chosen leaves, and typing flattens the tree to matches at any depth.

FilterInputChip

Default

The three segments a chip is made of; inside FilterInput each one is separately clickable, which is how a committed filter gets edited.

With error

error reddens the chip for a value that was rejected. It is presentational only — the expression underneath is unchanged.

With long text

Long text in both segments. The chip caps at 320px; segments size to their content, with the attribute capped at 180px and the value guaranteed 60px minimum. When space is tight, the attribute shrinks first (since the value is what the filter matches on), both truncating with ellipsis rather than one segment collapsing to zero.

With value max width

A field with its own valueMaxWidth (here 500px) lifts the chip's blanket cap and lets the value segment run wide, truncating with an ellipsis only past that width — for long freeform values like parameter-path expressions (AS-1064). The full value is preserved for matching.

Realistic example

The same chip carrying real content, which is where the segment widths actually get tested.

And operator

The AND connector is itself a chip, clickable to change the join. Standalone it reads FilterInput context, so the story wraps it in a no-op provider.

Or operator

The OR connector, same shape — which is why AND/OR needs no separate control.

Combined with and

Two conditions and the connector between them: what the input assembles as each chip commits.

Combined with or

The same pair joined by OR, where the connector is the only difference between two very different queries.

With delete button

onRemove reveals the remove button on hover, so a resting filter row stays quiet.

Error with delete

Error plus remove — a rejected chip has to stay removable, since dropping it is usually the fastest fix.

Interactive delete example

Removing chips one at a time, with the connectors closing up behind them.

Disabled

disabled locks a chip: dimmed, no click, no remove, for a condition the surrounding page owns.

Disabled with on remove

disabled wins over onRemove — no remove button appears, so a locked chip cannot be dropped by accident.

Disabled and interactive mix

Locked and editable chips in one row, which is what a drill-down actually looks like.

Building attribute only

building is the half-made chip shown while a condition is being composed — attribute chosen, operator next.

Building with operator

One step on, waiting for a value.

Building complete

All three segments filled, at the point where the chip commits and stops building.

All states showcase

Every chip state in one frame — the quickest way to check a visual change has not shifted one of them.

Paired

A paired chip carries two triplets separated by a semicolon, for a field whose value means nothing without its key.

Paired with error

The error lands on the half that is wrong — here the required second value — rather than reddening the whole chip.

Paired with long text

The same cap, 380px across two triplets. The base value is held to 90px so it cannot hide its partner, but every other segment keeps its full width, so the second value is the one that gives way.

Composition

Default

The raw backend payload rendered as-is: around fifty fields, a hundred-plus application list, and the paired context-parameter field — the breadth the pattern has to survive.

Suggestions only

With strictValues: false everywhere, option lists become suggestions and any typed value commits, which is how the Attacks page treats the schema. Type checks and explicit validate callbacks still apply.

Simple

Two fields, to show the same component scales down — though at this size a pair of Selects is usually the better answer.

Backend integration

The schema arriving from a fetch: until fields exists there is nothing to filter by, so the input waits behind a placeholder block.

FilterInputFieldMenu

Default

The plain list — every field in the config, label first, whatever its type.

Few fields

A short config, to check the menu does not pad itself out.

Closed

open={false} renders nothing at all — no collapsed shell, no placeholder — so this frame is deliberately empty. It is the one story with no trigger.

Interactive

Selection wired up, so you can watch which field the menu hands back.

Typing filters the list by label and name, case-insensitively — try “status” or “CWE”.

With recent fields

recentConditions puts the last few filters back at the top, capped at three — what keeps a fifty-field menu usable day to day. Each row replays the whole condition, not just the field.

With suggestions

A curated suggestions section, for the handful of fields most people reach for first.

With groups

Fields under labelled group headers, in array order, with anything left out of every group falling into a trailing headerless section — here, CWE.

With descriptions

Hovering or keyboard-focusing a row opens a popover beside the menu with the description and, where the value format is not obvious, an example. A row with no description opens nothing, and group headers are inert.

With scrollable descriptions

A described list long enough to scroll, for checking the popover keeps up with the cursor and the keyboard.

With recent and suggestions

Both props set, and only Recent renders — the two shortcut sections are mutually exclusive, so suggestions are the fallback for someone with no history rather than a second row of shortcuts.

FilterInputOperatorMenu

String type

A string field: equality, substring matching, set membership, and the two presence checks.

Integer type

Numbers add the comparison operators, which is the usual reason to reach for a query builder at all, with in below the rule as its own group. between is not here — it is date-only.

Float type

Same comparisons as integer, minus in: picking an exact float out of a list is not a real query.

Date type

Dates are the only type that offers between, so a time window is one condition rather than two, and the comparisons read as before and after.

Boolean type

A boolean offers is / is not and the presence checks, and nothing else is worth asking.

Enum type

An enum trades comparison for set membership: is one of / is not one of is the operator that earns its place here.

Interactive

Selection wired up, with the chosen operator echoed beside the trigger.

Keyboard navigation

Arrow keys move, Enter selects, Escape closes — the menu is fully operable without a pointer once the trigger has opened it.

Props

PropTypeDefaultDescription
fieldsFieldMetadata[] | undefinedFilter-field configurations driving the autocomplete. A few names are reserved and auto-wired with design-system helpers — DS-supplied callbacks override consumer values for the reserved slots, because the field semantics (mask range, accepted chars, backend form) are fixed by DS: - status_code — HTTP status code field (mask suggestions, format validation, digit-or-X input filter, partial-input normalization). To opt out, use a different name and attach the factories (createStatusCodeSuggestions, …) manually.
fieldGroupsFieldGroup[] | undefinedOptional grouping for the field-selection menu. When omitted, fields render as a flat list. When provided, fields render under labeled group headers (group order = array order; field order = listed order). Fields not referenced by any group fall into a trailing headerless section. Referenced by field name; unknown names are ignored.
valueExprNode | null | undefined
onChange((expression: ExprNode | null) => void) | undefined
placeholderstring | undefinedType to filter...
errorboolean | undefinedfalse
externalErrorsstring[] | undefinedField names whose values were rejected by the backend. Matching chips are rendered with a value error (red). Purely presentational: conditions and onChange output are unaffected, and the consumer is expected to render its own message (e.g. an alert with the backend error text) and clear the prop when the filter changes or the query succeeds.
onErrorsChange((errors: string[]) => void) | undefinedNotified whenever the set of validation messages FilterInput renders below the input changes (empty array = no visible error). Lets a consumer avoid stacking its own message (e.g. a backend-error alert) on top of one the input already shows. Pass a stable (memoized) callback.
showKeyboardHintboolean | undefinedfalse
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
data-testidstring | undefined

FilterInputChip

PropTypeDefaultDescription
chipIdstring | undefined
attribute *string
attributeDescriptionstring | undefinedDescription shown in a dark tooltip on hover of the attribute segment. When absent, no tooltip renders. The operator/value segments are unaffected (AS-1060).
operatorstring | undefined
valuestring | undefined
errorChipErrorSegment | undefinedfalse
valuePartsstring[] | undefined
valueSeparatorstring | undefined
errorValueIndicesnumber[] | undefined
buildingboolean | undefinedfalse
disabledboolean | undefinedfalseWhen true, the chip cannot be edited or removed (dimmed appearance)
valueMaxWidthnumber | undefined500Caps the applied value segment at this width (px), truncating with an ellipsis; lifts the chip's default max-width so it grows to fit. Defaults to 500; a paired chip caps its whole width there instead (AS-1064).
caretMode"end" | undefinedendCaret placement on value inline-edit: 'end' (default) puts it at the tail — better for long values; pass explicitly to keep the API visible (AS-1064).
paircomplexSecond paired triplet (two-step fields). The paired attribute is fixed.
onRemove(() => void) | undefined
onSegmentClickcomplex
onPairSegmentClickcomplexClick on an editable paired segment (operator/value of the second triplet).
titlestring | undefined
defaultCheckedboolean | undefined
defaultValuestring | number | readonly string[] | undefined
autoFocusboolean | undefined
idstring | undefined
tabIndexnumber | undefined
relstring | undefined
onChangeChangeEventHandler<T, Element> | undefined
data-testidstring | undefined

FilterInputFieldMenu

PropTypeDefaultDescription
fields *FieldMetadata[]
filterTextstring | undefinedText from the input to filter displayed fields
onSelect *(field: FieldMetadata) => void
openboolean | undefinedfalse
onOpenChange((open: boolean) => void) | undefined
recentConditionsCondition[] | undefined[]
suggestedFieldsFieldMetadata[] | undefined[]
fieldGroupsFieldGroup[] | undefinedOptional grouping for the field list. When omitted, fields render flat.
onSelectAnd(() => void) | undefined
onSelectOr(() => void) | undefined
onEscape(() => void) | undefined
positioningRecord<string, unknown> | undefined
inputRefRefObject<HTMLInputElement | null> | undefinedRef to the query bar input — ArrowUp on first item returns focus here
menuRefRefObject<HTMLDivElement | null> | undefinedRef to the menu content (shared across menus for focus management).
data-testidstring | undefined

FilterInputOperatorMenu

PropTypeDefaultDescription
fieldType *FieldTypeThe field type to determine which operators to show
operatorsFilterOperator[] | undefinedOptional list of operators from field config. When provided, only these operators are shown (preserving type-based grouping). Falls back to OPERATORS_BY_TYPE[fieldType] when not set.
onSelect *(operator: FilterOperator) => voidCallback when an operator is selected
openboolean | undefinedfalseWhether the menu is open
onOpenChange((open: boolean) => void) | undefinedCallback when open state should change
onEscape(() => void) | undefinedCallback when Escape is pressed (discard)
positioningRecord<string, unknown> | undefinedOverride positioning config for the dropdown
inputRefRefObject<HTMLInputElement | null> | undefinedRef to the query bar input — ArrowUp on first item returns focus here
filterTextstring | undefinedText to filter operators by label
menuRefRefObject<HTMLDivElement | null> | undefinedRef to the menu content element — shared across menus for focus management
data-testidstring | undefined

FilterInputValueMenu

PropTypeDefaultDescription
values *ValueOption[]
onSelect *(value: ConditionValue) => void
onCommit((values: ConditionValue[]) => void) | undefined
openboolean | undefined
onOpenChange((open: boolean) => void) | undefined
multiSelectboolean | undefined
initialValuesConditionValue[] | undefined
highlightValueConditionValue | undefined
onEscape(() => void) | undefined
widthnumber | "standard" | "compact" | undefined
positioningRecord<string, unknown> | undefined
onBuildingValueChange((preview: string | undefined) => void) | undefined
onItemToggle(() => void) | undefinedFires only on user-initiated multi-select toggle (not on init).
inputRefRefObject<HTMLInputElement | null> | undefinedQuery bar input — ArrowUp on first item returns focus here.
filterTextstring | undefinedFilter values by label.
loadingboolean | undefinedOptions are still loading — show a loading indicator instead of the list.
emptyLabelstring | undefinedReplaces the empty-state's default "No results" text.
menuRefRefObject<HTMLDivElement | null> | undefinedMenu content ref (shared across menus for focus management).
blurCommitRefRefObject<(() => boolean) | null> | undefinedSet here so blur handler can commit multi-select values.