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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LilyDesignSystem.Blazor.Filter" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LilyDesignSystem.Blazor.Filter" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="LilyDesignSystem.Blazor.Filter" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add LilyDesignSystem.Blazor.Filter --version 0.1.0
                    
#r "nuget: LilyDesignSystem.Blazor.Filter, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package LilyDesignSystem.Blazor.Filter@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=LilyDesignSystem.Blazor.Filter&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=LilyDesignSystem.Blazor.Filter&version=0.1.0
                    
Install as a Cake Tool

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 group per level; each condition a group named by labels.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.
  • readonly shows 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-Value works 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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