LilyDesignSystem.Blazor.Filter
0.1.0
dotnet add package LilyDesignSystem.Blazor.Filter --version 0.1.0
NuGet\Install-Package LilyDesignSystem.Blazor.Filter -Version 0.1.0
<PackageReference Include="LilyDesignSystem.Blazor.Filter" Version="0.1.0" />
<PackageVersion Include="LilyDesignSystem.Blazor.Filter" Version="0.1.0" />
<PackageReference Include="LilyDesignSystem.Blazor.Filter" />
paket add LilyDesignSystem.Blazor.Filter --version 0.1.0
#r "nuget: LilyDesignSystem.Blazor.Filter, 0.1.0"
#:package LilyDesignSystem.Blazor.Filter@0.1.0
#addin nuget:?package=LilyDesignSystem.Blazor.Filter&version=0.1.0
#tool nuget:?package=LilyDesignSystem.Blazor.Filter&version=0.1.0
Filter (Blazor helper)
A headless filter builder for Blazor: the user composes conditions (a field, an operator, a value) into groups joined by and / or, and the result comes out as JSON, SQL, MongoDB, OData or an in-memory predicate. It ships semantic HTML, ARIA and focus management, no CSS, and no English: every string is a prop.
Source: lily-design-system, package LilyDesignSystem.Blazor.Filter. Contract: spec/index.md.
Install
dotnet add package LilyDesignSystem.Blazor.Filter
Quick start
@using LilyDesignSystem.Blazor.Helpers
<FilterBuilder Label="Filter people" Fields="fields" @bind-Value="filter" Labels="labels" Format="FilterOutputFormat.Sql" Dialect="SqlDialect.Postgres" />
@code {
private readonly FilterField[] fields =
{
new() { Id = "name", Label = "Name" },
new() { Id = "age", Label = "Age", Type = FilterFieldType.Number },
new() { Id = "joined", Label = "Joined", Type = FilterFieldType.Date, Column = "joined_on" },
new() { Id = "team", Label = "Team", Type = FilterFieldType.Select, Options = new[] { new FilterOption("red", "Red"), new FilterOption("blue", "Blue") } },
new() { Id = "active", Label = "Active", Type = FilterFieldType.Boolean },
};
private FilterGroup filter = FilterModel.EmptyFilter();
private FilterLabels labels = /* see Labels */ default!;
// SqlResult where = FilterModel.ToSql(filter, fields, SqlDialect.Postgres); // Sql + Params
// var passes = FilterModel.ToPredicate(filter, fields); // row => bool
}
labels is required and has no default (see Labels).
Fields and operators
| Type | Value | Operators |
|---|---|---|
text (default) |
text | contains, does not contain, equals, not equals, starts with, ends with, is empty, is not empty |
number |
number | equals, not equals, greater than, at least (lower limit), less than, at most (upper limit), between, not between, is empty, is not empty |
date |
ISO YYYY-MM-DD |
the same as number — a date range is between |
select |
an option id | equals, not equals, is one of, is none of, is empty, is not empty |
boolean |
— | is true, is false, is empty, is not empty |
A field's operators can restrict the list (operators: ["gte", "lte"] for a limit-only field), column names it in SQL / MongoDB / OData, and options supplies a select's choices.
Output
The function names below are the TypeScript ones. In C# they are PascalCase static methods of
FilterModel(ToJson,FromJson,ToSql,ToMongo,ToOData,ToPredicate,FormatFilter), and the options are arguments (ToSql(filter, fields, SqlDialect.Postgres, inline: false)).
All pure functions over the filter value — use them with or without the component:
| Function | Result |
|---|---|
toJson(filter, fields) |
plain, id-free { combinator, not?, rules: [...] }, or null when empty; fromJson reads it back (reporting what it cannot) |
toSql(filter, fields, { dialect, inline }) |
{ sql, params } — the WHERE condition without the word; values are parameters (?, $1, @p1 by dialect) |
toMongo(filter, fields) |
a MongoDB query document |
toOData(filter, fields) |
an OData $filter expression |
toPredicate(filter, fields) |
(row) => boolean over rows keyed by field id; an empty filter passes every row |
formatFilter(filter, fields, format, dialect) |
any of them as display text (SQL with values inline) |
An incomplete condition (no value yet, a bad date, a range the wrong way round) is a normal state while the user types: it is shown, flagged by nothing, and left out of every output until it is finished. Dialects: ansi, postgres, mysql, sqlite, mssql.
SQL safety
Values are always parameters. Column names come only from the declared fields, and must be plain identifiers (letters, digits, _, dots) or toSql throws FilterError. LIKE text has %, _ and \ escaped. inline: true writes the values into the text with quotes doubled — for showing and logging only, never for running against a database.
Labels
const labels: FilterLabels = {
rule: (n) => `Condition ${n}`, group: (depth) => `Group, level ${depth}`,
field: "Field", operator: "Operator",
operatorName: (op) => names[op], value: "Value", valueFrom: "From", valueTo: "To",
combinator: "Match", and: "all", or: "any", not: "Not",
addRule: "Add condition", addGroup: "Add group",
removeRule: (n) => `Remove condition ${n}`, removeGroup: (depth) => `Remove group, level ${depth}`,
// optional: choose, empty, output (names the text output), ruleAdded / ruleRemoved / groupAdded / groupRemoved (announcements)
};
Behaviour
- Markup: a labelled
groupper level; each condition agroupnamed bylabels.rule(n)holding named<select>s and an input of the type's kind (text,number,date, a<select>, or a checkbox list for is one of); add and remove are real buttons. - Focus: adding a condition focuses its field select; removing one returns focus to the group's Add condition.
- Announcements through a polite status region, only when the label is given.
readonlyshows the filter without controls to change it;maxDepth(default 3) bounds nesting.- The value is immutable data: every change is a new object, and what did not change is shared, so
@bind-Valueworks with your own state, a store or a URL.
Styling hooks
filter, filter-group, filter-group-header, filter-combinator, filter-not, filter-rules, filter-item, filter-rule, filter-field, filter-operator, filter-value, filter-value-to, filter-choices, filter-choice, filter-add-rule-button, filter-add-group-button, filter-remove-rule-button, filter-remove-group-button, filter-empty, filter-output, filter-output-text, filter-status; data-depth, data-readonly, data-format.
Non-goals
Saved filters and persistence, a server round trip, free-text query parsing, locale-aware number and date entry (the consumer's input), and drawing — all the consumer's.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- LilyDesignSystem.Blazor.DataGrid (>= 0.10.0)
- Microsoft.AspNetCore.Components.Web (>= 10.0.12)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0 | 101 | 10/17/2026 |