Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelogKontakt
    1. Startseite
    2. Blog
    3. Komponenten-Guides
    4. React Filter Builder: AND/OR-Chips, gespeicherte Ansichten
    Read in English
    1. Blog
    2. Komponenten-Guides
    3. React Filter Builder: AND/OR-Chips, gespeicherte Ansichten
    Komponenten-Guides
    Komponenten-Guides

    React Filter Builder: AND/OR-Chips, gespeicherte Ansichten

    SR
    Serban Rusu · Gründer von Wingo UI
    6. Nov. 2026 · 11 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Was ist ein Filter Builder, und wann brauchst du einen?
    2. Hat shadcn einen Filter Builder?
    3. Wie fügst du einer React-Liste einen Filter Builder hinzu?
    4. Welche Props sind am wichtigsten?
    5. Wie funktionieren gespeicherte Ansichten?
    6. Wie verbindest du ihn mit einer Data Table?
    7. Wie führst du den Filter auf dem Server aus?
    8. Wie verhält er sich auf dem Smartphone?
    9. Wann ist ein einfaches Filter Panel die bessere UI?
    10. Was sind die typischen Fallstricke?
    11. Wo du anfängst
    12. Häufige Fragen
      1. Was ist der Unterschied zwischen einem Filter Builder und einem Query Builder?
      2. Hat shadcn/ui eine Filter-Builder-Komponente?
      3. Wie speichere ich einen Filter in der URL?
      4. Sollen Filter sofort greifen oder erst mit einem Apply-Button?
      5. Wie filtere ich eine React-Tabelle mit AND / OR-Bedingungen auf dem Server?

    Kurz gesagt

    Mit einem React Filter Builder kombinieren Nutzer Bedingungen (Feld, Operator, Wert) mit AND / OR, verschachteln eine Gruppe, speichern das Ergebnis als benannte Ansicht und sehen schon beim Bearbeiten, wie viele Zeilen passen. Er gehört in Backoffice-Listen, in denen Power-User Fragen stellen wie „überfällig oder über $5,000, in Chicago“. Für Kunden, die durch einen Katalog stöbern, ist ein Filter Panel mit Facetten, Checkboxen und Preisbereich die bessere UI.

    Veröffentlicht am 6. Nov. 2026

    Ein React Filter Builder ist die Leiste über einer Liste, in der Nutzer Bedingungen nacheinander hinzufügen: Stadt ist Chicago, Saldo mindestens $5,000, letzte Rechnung in den letzten 30 Tagen. Jede Bedingung wird zu einem Chip, die Chips werden mit AND oder OR verknüpft, und die Zahl daneben sagt, wie viele Zeilen übrig sind. Das Muster kennst du aus Issue-Trackern und tabellenartigen Datenbanken, und genau danach fragen Backoffice-Nutzer, sobald ein Suchfeld und ein Status-Dropdown nicht mehr reichen. Dieser Guide zeigt, wie du einen mit dem Filter Builder von Wingo UI baust, wie du ihn an eine Data Table und an einen Server anbindest und wann ein schlichtes Filter Panel die bessere Wahl ist.

    Was ist ein Filter Builder, und wann brauchst du einen?

    Ein Filter Builder bearbeitet einen kleinen Baum: eine Wurzelgruppe mit einem Kombinator (and oder or) und einer Liste von Bedingungen. Jede Bedingung besteht aus Feld, Operator und Wert. Eine verschachtelte Gruppe bringt Klammern ins Spiel, „in Chicago und (überfällig oder Saldo über $5,000)“ ist also ein AND an der Wurzel mit einer Bedingung und einer OR-Gruppe darin.

    Du brauchst einen, wenn sich die Fragen an eine Liste von Tag zu Tag ändern und Zahlen, Datumswerte oder ein OR enthalten. Sales Ops filtert Kunden, der Support Tickets, die Buchhaltung Rechnungen: Niemand will für jede Frage einen neuen, fest verdrahteten Tab. Braucht deine Liste nur „Status ist X“ und eine Suche, kann die Data Table das schon mit ihren Spaltenfiltern und Quick-Filter-Chips, und ein Builder wäre unnötiger Ballast. Welche Filter-UI für welchen Zweck passt:

    Nutzer sollenNimm
    suchen und ein oder zwei Status umschaltenSuche, Spaltenfilter und quickFilters der Data Table
    einen Katalog nach Facetten durchstöbern (Preis, Marke, Zustand, Entfernung)Filter Panel
    beliebige Felder mit Operatoren, AND / OR und gespeicherten Ansichten kombinierenFilter Builder
    eine Abfrage speichern, die eine Automation steuert („wenn X, dann Y“)Rule Builder

    Hat shadcn einen Filter Builder?

    Nein. Der Data-Table-Guide von shadcn (opens in a new tab) (geprüft am 6. November 2026) fügt ein Textfeld hinzu, das die E-Mail-Spalte über TanStack Table filtert, und sagt, dass du andere Spalten auf dieselbe Weise filtern kannst. Facettenfilter, AND / OR-Bedingungen und gespeicherte Ansichten gehören nicht dazu. „shadcn filters“ oder ein „shadcn data table filter“ mit Bedingungen heißt in der Praxis also: ein Registry-Item auswählen oder selbst schreiben.

    Wenn du nach „react query builder shadcn“ suchst, landest du bei React Query Builder (opens in a new tab). Stand 6. November 2026 liefert das Projekt Kompatibilitätspakete für Ant Design, Chakra UI, Mantine, MUI und weitere, dazu ein shadcn-Registry-Item, das du mit npx shadcn add https://react-querybuilder.js.org/r/query-builder.json installierst. Laut QueryBuilder-Doku (opens in a new tab) steht maxLevels standardmäßig auf unbegrenzter Verschachtelung, und zwischen den Regeln sind unabhängige Kombinatoren möglich. Die Export-Doku (opens in a new tab) nennt Ziele für formatQuery wie SQL, Prisma, Drizzle, MongoDB, CEL und JsonLogic. Das ist das bessere Werkzeug, wenn du einen kompletten Regelbaum brauchst, den du speicherst und als Abfrage ausführst, etwa in einem Reporting-Tool. Was direkt an der Liste passiert, deckt es nicht ab: Chips, Trefferzahl, gespeicherte Ansichten oder ein Smartphone-Layout. Um genau diese Seite geht es im Rest dieses Guides.

    Wie fügst du einer React-Liste einen Filter Builder hinzu?

    Installier ihn mit der CLI. Sie bringt lib/filters (Filtermodell, Auswertung und Serialisierung) und die Editoren mit, die er nutzt:

    bash
    npx wingo-ui@latest add filter-builder

    Beschreib deine Felder einmal. Jedes Feld hat eine id (den Schlüssel in der Zeile oder einen accessor), ein label und einen type: text, number, currency, date, select, multi-select oder boolean. Der Typ bestimmt, welche Operatoren das Feld anbietet und welcher Editor aufgeht: ein Textfeld, ein Zahlen- oder Betragsfeld, ein Kalender mit Schnellauswahl oder eine durchsuchbare Checkliste.

    tsx
    "use client"
    import { useMemo, useState } from "react"
    import { CalendarDays, MapPin, Wallet } from "lucide-react"
    import { FilterBuilder, type FilterBuilderField, type FilterGroup, type FilterView } from "@/components/ui/filter-builder"
    import { applyFilter, createFilterCondition, createFilterGroup } from "@/lib/filters"
    type Client = { id: string; name: string; city: string; status: string; balance: number; lastInvoice: string | null }
    const FIELDS: FilterBuilderField<Client>[] = [
    { id: "name", label: "Kunde", type: "text", group: "Kunde" },
    {
    id: "city",
    label: "Stadt",
    type: "select",
    icon: <MapPin />,
    group: "Kunde",
    options: [
    { value: "New York", label: "New York" },
    { value: "Chicago", label: "Chicago" },
    { value: "Austin", label: "Austin" },
    ],
    },
    {
    id: "status",
    label: "Status",
    type: "select",
    group: "Kunde",
    options: [
    { value: "active", label: "Aktiv", color: "#15803D" },
    { value: "overdue", label: "Überfällig", color: "#DC2626" },
    ],
    },
    { id: "balance", label: "Saldo", type: "currency", currency: "USD", icon: <Wallet />, group: "Finanzen" },
    { id: "lastInvoice", label: "Letzte Rechnung", type: "date", icon: <CalendarDays />, group: "Finanzen" },
    ]
    const VIEWS: FilterView[] = [
    {
    id: "overdue",
    name: "Überfällig",
    readOnly: true,
    pinned: true,
    filter: createFilterGroup("and", [createFilterCondition(FIELDS[2], { operator: "is", value: "overdue" })]),
    },
    ]
    export function ClientFilters({ clients }: { clients: Client[] }) {
    const [filter, setFilter] = useState<FilterGroup>(() => createFilterGroup("and"))
    const rows = useMemo(() => applyFilter(clients, filter, FIELDS), [clients, filter])
    return (
    <FilterBuilder
    fields={FIELDS}
    value={filter}
    onValueChange={setFilter}
    views={VIEWS}
    resultCount={rows.length}
    previewCount={(draft) => applyFilter(clients, draft, FIELDS).length}
    locale="en-US"
    shortcut="shift+f"
    labels={{ allRecords: "Alle Kunden" }}
    />
    )
    }

    applyFilter wendet denselben Baum auf deine Zeilen an: Textvergleiche ignorieren Groß- und Kleinschreibung sowie Akzente, Datumswerte werden nach lokalem Tag verglichen, und unvollständige Bedingungen werden übersprungen. Ein halb ausgefüllter Chip leert die Liste also nie. Mit previewCount zeigt das Sheet auf dem Smartphone schon „Show 3 results“, bevor irgendetwas angewendet ist.

    Die Demo startet mit den Chips „Status is Active“ und „Balance at least $5,000“. Drück auf „+ Filter“ (oder Shift+F), wähl „City“ und hak Chicago an: Der Chip erscheint mit geöffnetem Editor, und die Zahl aktualisiert sich. Klick auf das „and“ zwischen den ersten beiden Chips, um den ganzen Filter auf „or“ umzustellen
    $ npx wingo-ui@latest add filter-builder
    ProDoku: Filter Builder

    Welche Props sind am wichtigsten?

    Sechs Props bestimmen, wie sich der Builder verhält; der Rest betrifft das Aussehen (size, radius, tone) und den kontrollierten State.

    • variant: chips (der Standard) setzt jede Bedingung inline mit einem eigenen Editor-Popover. panel zeigt einen einzigen Filters-Button mit Zähler, der einen Editor mit Zeilen öffnet (eine Zeile pro Bedingung). Dort lassen sich verschachtelte Gruppen am leichtesten bearbeiten.
    • applyMode: instant ruft onValueChange bei jeder vollständigen Änderung auf (Text nach 300ms Pause). apply hält einen Entwurf mit Cancel und Apply. Das willst du, wenn jede Änderung einen Request kostet.
    • allowOr und allowGroups: Beide stehen standardmäßig auf true. Schalte OR für Zielgruppen ab, die es nie brauchen; der Builder bleibt dann eine schlichte AND-Liste. Gruppen gehen eine Ebene tief. Das reicht für „A und (B oder C)“, ohne dass aus der UI ein Baumeditor wird.
    • resultCount und loading: Die Zahl steht in einer Live-Region mit aria-live polite, Screenreader hören nach jeder Änderung also „24 results“. loading zeigt einen Spinner, während der Server antwortet.
    • maxChips: Auf dem Desktop wandern Chips über dieser Zahl in einen „+3“-Chip, der das Panel öffnet.
    • labels: alle Texte, standardmäßig Englisch. Die Prop nimmt ein Teilobjekt, du gibst also nur die Schlüssel mit, die du übersetzt; DEFAULT_FILTER_BUILDER_LABELS enthält den kompletten englischen Satz.

    Felder können ihre Operatoren außerdem mit operators: [...] einschränken. Mach das, wenn der Server nur einen Teil davon unterstützt, damit niemand einen Filter baut, den dein Backend stillschweigend ignoriert.

    Die Panel-Variante: Öffne „Filters“, füg eine Bedingung hinzu und bau dann mit „Add group“ (Balance mindestens $5,000 oder Last invoice in den letzten 7 Tagen)
    $ npx wingo-ui@latest add filter-builder
    ProDoku: Filter Builder

    Wie funktionieren gespeicherte Ansichten?

    Eine Ansicht ist ein benannter Filter: { id, name, filter, readOnly?, pinned? }. Gib die Ansichten in views mit, und das Ansichtsmenü listet sie auf, angepinnte zuerst, ganz oben „All records“. Wer eine auswählt, ersetzt damit den Filter. Wird sie danach bearbeitet, steht „(modified)“ dahinter, und das Menü bietet Save changes oder Save as new view an.

    Das Speichern implementierst du selbst, denn nur deine App weiß, wo Ansichten (Saved Views) liegen. Gib die gespeicherte Ansicht aus onSaveView zurück, dann wird sie aktiv. Wird das Promise abgelehnt, lässt der Builder das Namensfeld offen und meldet den Fehler, damit nichts verloren geht, was der Nutzer getippt hat. Ein abgelehntes onDeleteView meldet seinen eigenen Fehler und lässt die Ansicht im Menü.

    tsx
    import { serializeFilter } from "@/lib/filters"
    export function ClientFiltersWithViews({ clients }: { clients: Client[] }) {
    const [filter, setFilter] = useState<FilterGroup>(() => createFilterGroup("and"))
    const [views, setViews] = useState<FilterView[]>(VIEWS)
    const [activeViewId, setActiveViewId] = useState<string | null>(null)
    const rows = useMemo(() => applyFilter(clients, filter, FIELDS), [clients, filter])
    return (
    <FilterBuilder
    fields={FIELDS}
    value={filter}
    onValueChange={setFilter}
    resultCount={rows.length}
    views={views}
    activeViewId={activeViewId}
    onActiveViewChange={setActiveViewId}
    onSaveView={async ({ name, filter: draft, id }) => {
    const res = await fetch("/api/views", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ id, name, filter: serializeFilter(draft) }),
    })
    if (!res.ok) throw new Error("Die Ansicht konnte nicht gespeichert werden")
    const saved: FilterView = { id: (await res.json()).id, name, filter: draft }
    setViews((list) => [...list.filter((v) => v.id !== saved.id), saved])
    return saved
    }}
    onDeleteView={async (viewId) => {
    const res = await fetch(`/api/views/${viewId}`, { method: "DELETE" })
    if (!res.ok) throw new Error("Die Ansicht konnte nicht gelöscht werden")
    setViews((list) => list.filter((v) => v.id !== viewId))
    }}
    />
    )
    }

    serializeFilter (aus @/lib/filters) macht aus dem Baum einen kurzen, URL-sicheren String, und parseFilter liest ihn wieder ein. Derselbe String funktioniert für Links mit ?filter=. So fügt jemand aus deinem Team die URL ein und sieht genau die Liste, die du gesehen hast.

    Wie verbindest du ihn mit einer Data Table?

    Halte den Filter-State oberhalb beider Komponenten und gib die gefilterten Zeilen nach unten weiter. Die Tabelle behält ihre eigene Suche, Sortierung, Auswahl und die Karten auf dem Smartphone; der Builder entscheidet, welche Zeilen sie bekommt.

    tsx
    import { DataTable, createColumns } from "@/components/ui/data-table"
    const col = createColumns<Client>()
    const columns = col([
    col.accessor("name", { header: "Kunde" }),
    col.accessor("city", { header: "Stadt" }),
    col.accessor("balance", { header: "Saldo", type: "currency", footer: "sum" }),
    col.accessor("lastInvoice", { header: "Letzte Rechnung", type: "relative" }),
    ])
    export function ClientsScreen({ clients }: { clients: Client[] }) {
    const [filter, setFilter] = useState<FilterGroup>(() => createFilterGroup("and"))
    const rows = useMemo(() => applyFilter(clients, filter, FIELDS), [clients, filter])
    return (
    <div className="flex flex-col gap-3">
    <FilterBuilder fields={FIELDS} value={filter} onValueChange={setFilter} resultCount={rows.length} locale="en-US" />
    <DataTable data={rows} columns={columns} caption="Kunden" locale="en-US" searchPlaceholder="Kunden suchen" />
    </div>
    )
    }

    Lass die filter-Optionen pro Spalte in der Tabelle weg, wenn der Builder da ist. So gibt es einen Ort zum Filtern statt zwei, die sich widersprechen. Für Listen mit Tausenden Zeilen, die im Browser bleiben, ist das alles. Für die TanStack-Seite der Tabelle selbst lies den Walkthrough zur Data Table mit TanStack Table v9.

    Wie führst du den Filter auf dem Server aus?

    In lib/filters steckt kein React, also funktioniert dasselbe parseFilter auch in einem Route Handler. Für eine Datenbank läufst du durch den Baum und machst aus jeder Bedingung eine parametrisierte Klausel. Der wichtige Teil ist die Whitelist: Feld-IDs werden auf bekannte Spalten abgebildet, und alles Unbekannte fliegt raus, statt in den SQL-String zu wandern.

    ts
    // app/api/clients/route.ts
    import { isFilterGroup, parseFilter, type FilterCondition, type FilterGroup } from "@/lib/filters"
    const COLUMNS: Record<string, string> = { name: "name", city: "city", status: "status", balance: "balance", lastInvoice: "last_invoice" }
    function conditionSql(c: FilterCondition, params: unknown[]): string | null {
    const column = COLUMNS[c.field]
    if (!column) return null
    const p = (value: unknown) => {
    params.push(value)
    return `$${params.length}`
    }
    const v = c.value
    switch (c.operator) {
    case "contains":
    return typeof v === "string" && v ? `${column} ILIKE ${p(`%${v.replace(/[%_\\]/g, "\\$&")}%`)}` : null
    case "is":
    return typeof v === "string" ? `${column} = ${p(v)}` : null
    case "any-of":
    return Array.isArray(v) && v.length ? `${column} = ANY(${p(v)})` : null
    case "gte":
    return typeof v === "number" ? `${column} >= ${p(v)}` : null
    case "lte":
    return typeof v === "number" ? `${column} <= ${p(v)}` : null
    case "in-last":
    // heute plus die v - 1 Tage davor, dasselbe Fenster wie in applyFilter
    return typeof v === "number" ? `${column} >= current_date - (${p(v)}::int - 1)` : null
    case "is-empty":
    return `${column} IS NULL`
    default:
    return null
    }
    }
    function toWhere(group: FilterGroup, params: unknown[]): string {
    const parts: string[] = []
    for (const node of group.conditions) {
    const sql = isFilterGroup(node) ? toWhere(node, params) : conditionSql(node, params)
    if (sql) parts.push(isFilterGroup(node) ? `(${sql})` : sql)
    }
    return parts.join(group.combinator === "or" ? " OR " : " AND ")
    }
    export async function GET(request: Request) {
    const filter = parseFilter(new URL(request.url).searchParams.get("filter"))
    const params: unknown[] = []
    const where = filter ? toWhere(filter, params) : ""
    // `SELECT ... FROM clients ${where ? `WHERE ${where}` : ""}` mit params über deinen Postgres-Client ausführen
    return Response.json({ where, params })
    }

    Auf dem Client schickst du serializeFilter(filter) aus onValueChange, setzt loading, solange der Request läuft, und gibst die Gesamtzahl aus der Antwort als resultCount weiter. Kombinier das mit applyMode="apply", wenn die Abfrage langsam ist. Beschränk die operators jedes Felds auf die Fälle, die dein switch behandelt, damit die UI nie einen anbietet, den der Server verwirft. Achte außerdem darauf, dass Client und Server Text gleich vergleichen: applyFilter ignoriert Groß- und Kleinschreibung sowie Akzente, = in Postgres tut beides nicht. Nimm also ILIKE, eine citext-Spalte oder unaccent(), wenn die Zahlen in Browser und Server übereinstimmen müssen.

    Wie verhält er sich auf dem Smartphone?

    Unter 768px bleiben die Chips sichtbar und scrollen seitlich, jeder mit einem ×, das ihn sofort entfernt. Alles andere zieht in ein einziges Bottom Sheet hinter einem Filters-Button mit Zähler: Bedingungen als Zeilen, and / or als Segmented Control, und „+ Add filter“ führt mit einer kurzen Slide-Animation erst in die Feldliste und dann in den Editor. Nichts ändert sich, bis der Nutzer auf „Show 24 results“ tippt; wer das Sheet schließt, verwirft den Entwurf. Das ist Absicht: Ein Popover an einem 32px hohen Chip würde genau die Liste verdecken, die gefiltert werden soll, und ein Sofortfilter hinter einem Sheet in voller Höhe ändert eine Liste, die niemand sieht. Bei Touch-Bedienung wachsen die Touch-Ziele auf 44px. Setz responsive={false} nur, wenn deine App nur auf dem Desktop läuft.

    Wann ist ein einfaches Filter Panel die bessere UI?

    Wenn die Leute, die filtern, Kunden sind, die durch einen Katalog stöbern. Wer ein gebrauchtes Smartphone unter $300 sucht, will Apple anhaken, einen Preisbereich ziehen und „Show 1,240 results“ sehen; in Operatoren oder OR-Gruppen denkt dabei niemand. Dafür ist das Filter Panel gebaut: eine Seitenleiste mit Facetten, die auf dem Desktop jede Änderung direkt anwendet (Checkbox-Listen mit Zählern, Chips, Preis über einem Histogramm, Ort mit Radius, Schalter), und auf dem Smartphone ein Sheet in voller Höhe mit Live-Zähler.

    Hak eine Marke an, zieh die Preisregler und schalte „Delivery only“ um: Die Seitenleiste wendet jede Änderung an, und auf dem Smartphone öffnen sich dieselben Filter als Sheet mit einem „Show results“-Button samt Zähler
    $ npx wingo-ui@latest add filter-panel
    ProDoku: Filter panel

    Eine gute Faustregel: Wenn du jeden sinnvollen Filter vorab aufzählen kannst und jeder nur eine Handvoll Werte hat, nimm das Panel. Wenn Nutzer sich eigene Fragen ausdenken und speichern sollen, nimm den Builder. Manche Apps nutzen beides: das Panel im öffentlichen Katalog, den Builder im Admin-Bereich dahinter.

    Was sind die typischen Fallstricke?

    • Chips, die nichts filtern. Ein Chip mit Operator, aber ohne Wert sieht aktiv aus und ist es nicht. Der Builder entfernt einen unvollständigen Chip, sobald sein Editor zugeht; wenn du selbst einen baust, mach es genauso.
    • Zwei Filtersysteme auf einem Screen. Spaltenfilter im Tabellenkopf plus ein Builder darüber geben zwei Antworten auf die Frage „Warum ist diese Zeile ausgeblendet?“. Entscheide dich für eins.
    • OR ohne Klammern. „Chicago und überfällig oder VIP“ ist mehrdeutig. Halte OR an der Wurzel oder in einer sichtbaren Gruppe, und zeig den Filter als Satz (describeFilter in lib/filters schreibt ihn) dort, wo man ihn lesen kann.
    • Stille Lücken im Server. Ignoriert das Backend einen Operator, sehen Nutzer falsche Zahlen. Schränk operators pro Feld ein.
    • Keine Trefferzahl. Ohne „24 results“ weiß niemand, ob ein Filter überhaupt etwas bewirkt hat. Gib resultCount mit, und 0 ist eine echte Antwort.

    Mehr Guides wie diesen findest du in der Kategorie Komponenten-Guides, oder du startest mit dem Pillar-Artikel zu React-Formularkomponenten. Er nutzt dieselbe Feld-Anatomie wie die Editoren hier.

    Wo du anfängst

    Filter Builder, Data Table und Filter Panel sind Pro-Komponenten und in jedem Plan auf der Preisseite enthalten. Am schnellsten beurteilst du den Builder im Playground auf seiner Doku-Seite: Stell variant, applyMode und allowGroups um und schau, was sich ändert. Wenn er passt, installier ihn mit npx wingo-ui@latest add filter-builder und pass fields an deine eigene Liste an.

    Komponenten in diesem Artikel

    • Filter Builder

      A React filter builder for any list: condition chips, AND / OR, nested groups, saved views and a live count, with one bottom sheet on phones.

      Pro
    • Data Table

      A React data table on TanStack Table: search, filters, sorting, bulk actions, pinning, resizing, virtualization and cards on phones.

      Pro
    • Filter panel

      A React filter panel for faceted search: a sidebar that applies as you go on desktop, a full-height sheet with a live count on phones.

      Pro

    Häufige Fragen

    Was ist der Unterschied zwischen einem Filter Builder und einem Query Builder?

    Ein Query Builder bearbeitet meist einen kompletten Regelbaum mit beliebiger Verschachtelung und exportiert ihn nach SQL, MongoDB oder in eine andere Abfragesprache. Er passt also zu Admin-Tools, die Abfragen speichern. Ein Filter Builder ist die leichtere Variante direkt an der Liste: ein Chip pro Bedingung, AND / OR, eine Ebene Gruppen, gespeicherte Ansichten und eine Trefferzahl neben der Liste.

    Hat shadcn/ui eine Filter-Builder-Komponente?

    Nein. Stand November 2026 zeigt der Data-Table-Guide von shadcn ein Textfeld, das über TanStack Table eine Spalte filtert, und verweist für alles Weitere auf die TanStack-Doku. AND / OR-Bedingungen, verschachtelte Gruppen und gespeicherte Ansichten bleiben dir oder einem Registry-Item von Dritten überlassen.

    Wie speichere ich einen Filter in der URL?

    Serialisier den Filterbaum zu einem kurzen, URL-sicheren String und leg ihn in einen Query-Parameter wie ?filter=. In Wingo UI schreibt serializeFilter(filter) aus lib/filters den String, und parseFilter(text) liest ihn wieder ein. Bei einem veralteten oder von Hand bearbeiteten Link gibt es null zurück, und die Seite zeigt einfach die ungefilterte Liste.

    Sollen Filter sofort greifen oder erst mit einem Apply-Button?

    Lass sie sofort greifen, wenn Filtern billig ist, etwa bei einer Liste, die schon im Browser liegt. Dann sieht man die Wirkung jeder Änderung direkt. Nimm einen Apply-Button, wenn jede Änderung einen Server-Request oder eine langsame Abfrage kostet, und arbeite auf Smartphones immer mit einem Entwurf, weil der Filter-Editor dort die Liste verdeckt.

    Wie filtere ich eine React-Tabelle mit AND / OR-Bedingungen auf dem Server?

    Schick den Filterbaum an einen Endpoint, lauf rekursiv durch ihn und mach aus jeder Bedingung eine parametrisierte SQL-Klausel, verbunden mit AND oder OR, Gruppen in Klammern. Bilde Feld-IDs über eine Whitelist auf Spalten ab, damit ein Client nie einen Spaltennamen einschleusen oder einen Operator schicken kann, den du nicht unterstützt.

    In deinem Projekt ausprobieren

    Filter Builder

    Pro

    A React filter builder for any list: condition chips, AND / OR, nested groups, saved views and a live count, with one bottom sheet on phones.

    75 Komponenten kostenlos, ohne Konto. Pro ab 8 $ im Monat.

    Filter Builder live öffnenPreise ansehen
    • Filter Builder
    • Query Builder
    • Datentabelle
    • Gespeicherte Ansichten
    • React

    Teilen

    SR

    Über den Autor

    Serban Rusu

    Gründer von Wingo UI

    Serban Rusu hat Wingo UI gegründet. Er baut die Komponenten, die CLI und den MCP-Server und schreibt über React-UIs für Smartphones und KI-Agents.

    Mehr von Serban
    Weiterlesen

    Ähnliche Artikel

    Alle Artikel
    Komponenten-Guides

    Audit Log UI in React: Filter, Diffs und CSV-Export

    So baust du eine Audit Log UI in React, mit der man arbeiten kann: wer was an welchem Datensatz geändert hat, Tagesgruppen, Filter, Diffs und CSV-Export.

    SRSerban Rusu·6. Nov. 2026·10 Min. Lesezeit
    Komponenten-Guides

    React Editable Table: Spreadsheet-Grid oder Inline Edit

    So baust du eine React Editable Table wie eine Tabellenkalkulation: typisierte Zellen, Bereichsauswahl, Excel-Paste, Undo, Validierung oder Inline Edit.

    SRSerban Rusu·5. Nov. 2026·10 Min. Lesezeit
    Komponenten-Guides

    React Empty State: Erste Nutzung, keine Treffer, Fehler

    Bau eine React Empty State Komponente für erste Nutzung, keine Treffer und Fehler, mit Texten, die sagen, was passiert ist, und einer Aktion, die weiterhilft.

    SRSerban Rusu·19. Okt. 2026·9 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Artikel, Produktneuheiten und gelegentlich Angebote von Wingo UI. Wir zählen Klicks, damit es relevant bleibt.

    Kein Spam. Du kannst dich jederzeit abmelden.

    WingoUI

    Animierte, konfigurierbare, mobile-first React-Komponenten und Blöcke. Kopier den Quellcode, pass ihn an und lass deinen Coding-Agenten damit bauen.

    Produkt

    • Komponenten
    • Vorlagen
    • Preise
    • KI-Agenten
    • Für Teams
    • Theme-Generator

    Ressourcen

    • Doku
    • Kontakt
    • Programme
    • Blog
    • Changelog
    • Changelog-RSS
    • llms.txt

    Vergleiche

    • Wingo UI vs. Premium-Kits
    • Wingo UI vs. shadcn/ui
    • shadcn/ui-Alternativen
    • MUI-Alternativen
    • Tailwind-Plus-Alternativen
    • Magic-UI-Alternativen
    • Kostenlose Komponenten

    Rechtliches

    • AGB
    • Datenschutz
    • Rückerstattung
    • Lizenz
    • Impressum

    Komponenten-Kategorien

    • Buttons & Actions
    • Inputs
    • Forms
    • Navigation
    • Overlays
    • Feedback
    • Data Display
    • Tables & Lists
    • Charts & Stats
    • Layout
    • Media
    • AI Kit
    • Text & Effects
    • Mobile
    • Commerce
    • Marketing Sections
    • Blocks
    • Hooks & Utilities

    © 2026 Wingo UI

    Wingo UI