Zum Inhalt springen
    WingoUI
    KomponentenVorlagenDokuPreiseKI-AgentenBlogChangelog
    1. Startseite
    2. Blog
    3. Mobile UI mit React
    4. Responsive Tabelle: Zeilen als Karten auf dem Smartphone
    Read in English
    1. Blog
    2. Mobile UI mit React
    3. Responsive Tabelle: Zeilen als Karten auf dem Smartphone
    Mobile UI mit React
    Mobile UI mit React

    Responsive Tabelle: Zeilen als Karten auf dem Smartphone

    SR
    Serban Rusu · Gründer von Wingo UI
    9. Okt. 2026 · 11 Min. Lesezeit

    Auf dieser Seite

    0%
    1. Wann sollte eine Tabelle auf dem Smartphone zu Karten werden?
    2. Warum scheitert horizontales Scrollen bei Datensätzen?
    3. Welche Spalten schaffen es auf eine Karte?
    4. Wie machst du aus einer shadcn-Tabelle Karten auf dem Smartphone?
      1. Was ist mit dem reinen CSS-Trick über data-label?
    5. Wie funktionieren Sortierung und Sammelaktionen ohne Spaltenköpfe?
    6. Wie bekommst du dasselbe Layout mit Wingo UI?
      1. Wie geht die Data Table auf dem Smartphone mit Auswahl um?
    7. Was, wenn die Zeilen einfacher sind als eine Tabelle?
    8. Wie testest du eine responsive Tabelle auf dem Smartphone?
    9. Wo fängst du am besten an?
    10. Häufige Fragen
      1. Wie mache ich eine Tabelle auf dem Smartphone responsive?
      2. Ist die shadcn Table auf dem Smartphone responsive?
      3. Sollte ich display: block auf Tabellenzeilen setzen, um Karten zu bekommen?
      4. Wie sortieren Nutzer eine Tabelle auf dem Smartphone ohne Spaltenköpfe?
      5. Sollte ich mit useIsMobile zwischen Tabelle und Karten wechseln?

    Kurz gesagt

    Für eine responsive Tabelle auf dem Smartphone renderst du unter 768px jede Zeile als Karte: das wichtigste Feld als Titel, ein Status oder Betrag in der Ecke, zwei bis vier Paare aus Label und Wert und die Zeilenaktionen in einem Menü. Horizontales Scrollen behältst du nur für Raster, in denen Leute Spalte für Spalte vergleichen, etwa eine Zeiterfassung oder eine Preismatrix. Wechsle die Layouts über CSS-Breakpoints, damit schon das Server-HTML stimmt, und gib Sortierung, Auswahl und Sammelaktionen eigene Controls fürs Smartphone, denn Spaltenköpfe und Checkbox-Spalte sind dort weg.

    Veröffentlicht am 9. Okt. 2026

    Du lieferst eine Admin-Seite mit einer Tabelle aus sieben Spalten aus, öffnest sie auf dem Smartphone und siehst den Kundennamen, eine halbe Stadt und eine horizontale Scrollleiste. Bis du beim Betrag ankommst, sind die Spaltenköpfe weggescrollt, und niemand weiß mehr, welche Zahl zu welcher Zeile gehört. Eine gute responsive Tabelle ist auf dem Smartphone meist ein anderes Layout, keine schmalere Version derselben Tabelle. Dieses Tutorial zeigt, wann Zeilen zu Karten werden, welche Spalten es auf die Karte schaffen, wie du den Wechsel auf einer normalen shadcn/ui-Tabelle ohne Hydration-Flackern baust, und wie Sortierung, Auswahl und Sammelaktionen weiter funktionieren, wenn Spaltenköpfe und Checkbox-Spalte weg sind.

    Die Kurzfassung dieser Regel ist eine von neun in Mobile-first React-Komponenten. Dieser Beitrag ist die ausführliche Version.

    Wann sollte eine Tabelle auf dem Smartphone zu Karten werden?

    Wenn Leute einen Datensatz nach dem anderen lesen. Eine Liste von Kunden, Bestellungen, Rechnungen oder Tickets ist eine Liste von Datensätzen: Auf dem Smartphone suchst du den einen, den du brauchst, und öffnest ihn. Eine Karte pro Zeile zeigt alles Wichtige zu diesem Datensatz auf einen Blick, ohne seitliches Scrollen und ohne Spaltenkopf, den du dir merken musst.

    Behalte die Tabelle, wenn es darum geht, Werte über Zeilen und Spalten hinweg zu vergleichen. Eine Zeiterfassung, eine Preismatrix, ein monatliches Umsatzraster oder ein Funktionsvergleich ergeben nur Sinn, wenn die Spalten untereinander stehen, und Karten machen genau das kaputt. Lass solche Tabellen in ihrer eigenen Box seitwärts scrollen und fixiere die erste Spalte, damit jede Zeile ihren Namen behält.

    Was die Tabelle enthältLayout auf dem SmartphoneWarum
    Datensätze, die du öffnest (Kunden, Bestellungen, Tickets)KartenEin Datensatz auf einen Blick, Aktionen in Reichweite
    Zeilen eines Dokuments (Rechnungsposten, ein Beleg)Gestapelte Zeilen aus Label und WertLiest sich wie das gedruckte Dokument
    Ein Raster zum Vergleichen (Monate x Städte, Tarife x Funktionen)Horizontales Scrollen, erste Spalte fixiertAuf die Spalten kommt es an
    Die Details eines DatensatzesEine Description List, keine TabelleEs gibt nur eine Zeile

    Die letzte Zeile fängt einen häufigen Fehler ab: eine „Tabelle“ mit zwei Spalten, Label und Wert, die einen einzigen Kunden beschreibt. Das ist eine Description List. Die Description List stapelt auf Smartphones das Label über dem Wert und wechselt je nach Breite ihres Containers auf eine bis drei Spalten, sie passt also in eine schmale Karte in der Seitenleiste genauso wie auf eine ganze Seite.

    Warum scheitert horizontales Scrollen bei Datensätzen?

    Ein 390px breiter Screen zeigt zwei oder drei Spalten einer Admin-Tabelle gleichzeitig. Um einen Datensatz zu lesen, scrollen Leute nach rechts, verlieren die Namensspalte, scrollen zurück und wiederholen das für jede Zeile. Meist ist auch der Tabellenkopf vertikal aus dem Bild gescrollt, die Zahlen, bei denen sie ankommen, haben also kein Label. Jede Zeile kostet zwei Scrollrichtungen.

    Horizontales Scrollen ist außerdem das, was du standardmäßig bekommst. Ohne eigene Arbeit heißt shadcn table mobile responsive einfach Scrollen: Die Table von shadcn/ui legt das <table> in ein div mit relative w-full overflow-x-auto, eine breite Tabelle sprengt also nie das Seitenlayout, sie scrollt nur in dieser Box. Das ist der richtige Fallback und das richtige Layout für Vergleichsraster, aber bei einer Kundenliste bekommt das Smartphone damit die Desktop-Tabelle in einem Drittel der Breite.

    Welche Spalten schaffen es auf eine Karte?

    Fünf oder sechs, jede mit einem festen Platz. Geh deine Spalten durch und gib jeder eine Rolle:

    • Titel: das Feld, an dem Leute den Datensatz erkennen. Der Kundenname, die Bestellnummer, der Betreff des Tickets. Einer pro Karte.
    • Untertitel: die Zeile, die zwei ähnliche Titel unterscheidet, etwa die Stadt oder die E-Mail. Optional.
    • Meta: ein Wert in der oberen Ecke, nach dem Leute die Liste absuchen. Ein Status-Badge oder ein Betrag, nicht beides.
    • Felder: zwei bis vier Paare aus Label und Wert unter dem Titel. Nimm die, mit denen Leute entscheiden, ob sie den Datensatz öffnen.
    • Versteckt: alles andere. Interne IDs, Erstellungsdaten, Spalten, die es nur zum Sortieren auf dem Desktop gibt.

    Für eine Kundenliste mit Name, Steuernummer, Stadt, Status, Saldo, Letzte Rechnung, Betreuer und Erstellt heißt das: Name als Titel, Stadt als Untertitel, Status als Meta, Saldo, Letzte Rechnung und Betreuer als Felder, Steuernummer und Erstellt versteckt. Für die versteckten Spalten ist der Datensatz weiterhin nur einen Tap entfernt.

    Aktionen wandern in ein „⋯“-Menü in der Ecke der Karte, das sich als Bottom Sheet öffnet. Inline-Icon-Buttons in einer Zeile sind mit der Maus in Ordnung; auf einer Karte konkurrieren sie mit dem Titel um ein 44px großes Touch-Ziel.

    Wie machst du aus einer shadcn-Tabelle Karten auf dem Smartphone?

    Render die Tabelle und eine Liste von Karten aus denselben Daten und lass CSS eine davon auswählen. Hier ist die komplette Komponente auf der Standard-Tabelle von shadcn/ui (npx shadcn@latest add table), mit einem einfachen span für den Status, damit sie nichts weiter braucht:

    tsx
    // components/clients-table.tsx
    import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
    type Client = { id: string; name: string; city: string; status: "Aktiv" | "Überfällig"; balance: number; owner: string };
    const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
    function Status({ value }: { value: Client["status"] }) {
    const tone = value === "Überfällig" ? "bg-destructive/10 text-destructive" : "bg-muted text-muted-foreground";
    return <span className={`shrink-0 rounded-full px-2 py-0.5 text-xs font-medium ${tone}`}>{value}</span>;
    }
    export function ClientsTable({ clients }: { clients: Client[] }) {
    return (
    <>
    {/* Desktop und Tablets: die echte Tabelle */}
    <div className="hidden md:block">
    <Table>
    <TableHeader>
    <TableRow>
    <TableHead>Kunde</TableHead>
    <TableHead>Stadt</TableHead>
    <TableHead>Status</TableHead>
    <TableHead>Betreuer</TableHead>
    <TableHead className="text-right">Saldo</TableHead>
    </TableRow>
    </TableHeader>
    <TableBody>
    {clients.map((c) => (
    <TableRow key={c.id}>
    <TableCell className="font-medium">{c.name}</TableCell>
    <TableCell>{c.city}</TableCell>
    <TableCell>
    <Status value={c.status} />
    </TableCell>
    <TableCell>{c.owner}</TableCell>
    <TableCell className="text-right tabular-nums">{usd.format(c.balance)}</TableCell>
    </TableRow>
    ))}
    </TableBody>
    </Table>
    </div>
    {/* Smartphones: eine Karte pro Zeile */}
    <ul aria-label="Kunden" className="flex flex-col gap-2 md:hidden">
    {clients.map((c) => (
    <li key={c.id} className="rounded-2xl border p-4">
    <div className="flex items-start justify-between gap-3">
    <div className="min-w-0">
    <p className="font-semibold">{c.name}</p>
    <p className="truncate text-sm text-muted-foreground">{c.city}</p>
    </div>
    <Status value={c.status} />
    </div>
    <dl className="mt-3 grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
    <div>
    <dt className="text-xs text-muted-foreground">Saldo</dt>
    <dd className="tabular-nums">{usd.format(c.balance)}</dd>
    </div>
    <div>
    <dt className="text-xs text-muted-foreground">Betreuer</dt>
    <dd>{c.owner}</dd>
    </div>
    </dl>
    </li>
    ))}
    </ul>
    </>
    );
    }

    Das ist das ganze Muster „Tabelle als Karten“ auf dem Smartphone. Drei Details zählen mehr als das Styling.

    Der Wechsel ist ein CSS-Breakpoint. hidden md:block und md:hidden stehen beide im Server-HTML, ein Smartphone zeichnet die Karten also schon beim ersten Laden. Wechselst du stattdessen mit einem useIsMobile()-Hook, rendert der Server die Tabelle (dort ist der Hook false), das Smartphone zeigt sie, und die Karten ersetzen sie erst nach der Hydration. Der Guide zum use mobile Hook erklärt, warum das passiert und wo ein Hook trotzdem das richtige Werkzeug ist.

    Die Karten sind eine echte Liste. <ul> mit einem aria-label sagt einem Screenreader, wie viele Datensätze es gibt, und Paare aus <dt> und <dd> verknüpfen jeden Wert mit seinem Label. Wenn du die Tabelle mit display: none ausblendest, verschwindet sie auch aus dem Accessibility Tree, Screenreader-Nutzer auf dem Smartphone bekommen also dieselben Karten wie alle anderen und keine versteckte Tabelle.

    Beide Kopien werden gerendert, das DOM hält also jede Zeile doppelt. Bei 25 Zeilen pro Seite ist das nichts. Bei Hunderten paginierst oder virtualisierst du, oder du renderst das versteckte Layout erst bei Bedarf. Ab 200 Zeilen virtualisiert die Data Table von Wingo UI das sichtbare Layout und rendert im versteckten nur einen ersten Screen mit 30 Zeilen.

    Was ist mit dem reinen CSS-Trick über data-label?

    Die beliebte Alternative behält ein einziges <table>, setzt unter einem Breakpoint display: block auf Zeilen und Zellen und gibt jeden Spaltenkopf über td::before { content: attr(data-label) } aus. Das spart die zweite Kopie des Markups, hat aber zwei Haken. Ein geändertes display auf Tabellenelementen hat früher deren Tabellensemantik entfernt: Adrian Roselli hält in seinem seit Jahren gepflegten Testbeitrag fest, dass Safari sie bei jedem display-Wert verloren hat, bis Safari 17 das behoben hat, und laut seinem Update vom Oktober 2023 ist display: contents der einzige Wert, der noch Probleme machen kann (Tables, CSS Display Properties, and ARIA (opens in a new tab)). Und ein Screenreader kündigt weiterhin eine Tabelle mit sieben Spalten an, während der Screen einen Stapel Karten zeigt und die Labels im CSS stecken.

    Wenn du den Trick nutzt, teste mit VoiceOver auf einem iPhone und TalkBack auf Android. Wenn du das nicht testen kannst, ist die Version mit zwei Layouts oben der sicherere Standard.

    Wie funktionieren Sortierung und Sammelaktionen ohne Spaltenköpfe?

    Sie brauchen eigene Controls, denn die Dinge, auf die Leute am Desktop geklickt haben, sind weg. Plane jedes einzeln:

    • Sortierung: eine Reihe von Chips „Sortieren nach“ über den Karten, einer pro sortierbarer Spalte, ein Tap wechselt die Richtung. Oder, bei vielen sortierbaren Spalten, ein Sortieren-Button, der ein Bottom Sheet mit Einträgen wie „Saldo, absteigend“ und „Kunde, aufsteigend“ öffnet.
    • Filter: dieselbe Filter-UI wie am Desktop, nur in einem Bottom Sheet statt in einem Popover.
    • Auswahl: keine Checkbox-Spalte. Ein Long Press auf eine Karte startet die Auswahl (so machen es Gmail und Fotos auf Android), danach schaltet jeder Tap eine Karte um, und solange der Auswahlmodus aktiv ist, zeigt jede Karte eine Checkbox.
    • Sammelaktionen: eine Leiste, die unten am Screen schwebt, solange Zeilen ausgewählt sind, mit Padding für den Home-Indikator, statt eines Toolbar-Streifens oben, der längst weggescrollt ist.
    • Paginierung: „Mehr laden“ am Ende der Liste. Nummerierte Seiten mit 32px großen Buttons sind schwer zu treffen und unterbrechen den Scrollfluss.

    Ein Long Press ist unsichtbar, er darf also nicht der einzige Weg sein. Lass das „⋯“-Menü auf jeder Karte sichtbar, und wenn Auswahl wichtig ist, ergänze zusätzlich eine sichtbare Aktion „Auswählen“ in der Toolbar oder im Zeilenmenü.

    Wie bekommst du dasselbe Layout mit Wingo UI?

    Nimm die Table für kleine Tabellen, die nur Daten anzeigen, und die Data Table für Admin-Listen. Beide machen eine React Table mobile responsive ohne zweiten Markup-Zweig: Sie rendern die Desktop-Tabelle und das Smartphone-Layout ins Server-HTML und wechseln bei 768px per CSS, und beide verteilen die Kartenrollen aus deinen Spalten: Die erste Spalte ist der Titel, die letzte Zahlenspalte (in der Data Table hat die erste Badge-Spalte Vorrang) ist die Meta, und der Rest sind Felder, bis du mit mobile etwas anderes sagst.

    Hier eine Bestelltabelle, in der die Rollen ausgeschrieben sind:

    tsx
    // components/recent-orders.tsx
    "use client";
    import { Table, type TableColumn } from "@/components/ui/table";
    type Order = { id: string; customer: string; city: string; placed: string; items: number; total: number };
    const columns: TableColumn<Order>[] = [
    { key: "customer", header: "Kunde", sortable: true, mobile: "title" },
    { key: "city", header: "Stadt", mobile: "subtitle" },
    { key: "id", header: "Bestellung", mobile: "hidden" },
    { key: "placed", header: "Bestellt am", type: "date", sortable: true },
    { key: "items", header: "Artikel", type: "number" },
    { key: "total", header: "Summe", type: "currency", sortable: true, mobile: "meta" },
    ];
    export function RecentOrders({ orders }: { orders: Order[] }) {
    return <Table caption="Letzte Bestellungen" columns={columns} data={orders} locale="en-US" onRowClick={(order) => console.log(order.id)} />;
    }

    Auf dem Smartphone ist jede Bestellung eine Karte mit dem Kunden als Titel, der Stadt darunter, der Summe in der Ecke und „Bestellt am“ und „Artikel“ als Feldern. Die Bestellnummer gibt es nur am Desktop. Spalten nach dem vierten Feld wandern auf der Karte hinter einen Schalter „Mehr anzeigen“. Weil customer, placed und total sortierbar sind, erscheint über den Karten eine Reihe von Chips „Sortieren nach“, und onRowClick macht jede Karte zu einem einzigen Button, den Tastaturnutzer mit Tab erreichen.

    Unter 768px wird jeder Rechnungsposten zu einer Karte mit dem Betrag in der Ecke und Sortier-Chips darüber; auf einem breiten Screen ist es eine normale Tabelle mit sortierbaren Spaltenköpfen und einer Summenzeile
    $ npx wingo-ui@latest add table
    ProDoku: Table

    Die Demo ist eine Rechnung mit fünf Posten und Summen. Mach dein Fenster schmaler oder öffne die Seite auf dem Smartphone, dann siehst du die Karten und die separate Summenkarte. Für eine Optik wie auf einem Kassenbon listet mobileLayout="stack" Zeilen aus Label und Wert ohne Kartenrahmen, und mobileLayout="scroll" lässt die Tabelle für Vergleichsraster seitwärts scrollen, mit fixierter erster Spalte.

    Wie geht die Data Table auf dem Smartphone mit Auswahl um?

    So, wie es der vorige Abschnitt beschreibt. Mit selectionMode="multiple" wählt ein Long Press von etwa 450ms eine Karte aus, danach fügen Taps Karten hinzu oder entfernen sie, und die Sammelaktionen, die du aus bulkActions zurückgibst, schweben unten. Der Sortieren-Button in der Toolbar öffnet ein Bottom Sheet mit Optionen im Stil von „Saldo, absteigend“, Filter und Zeilenmenü öffnen sich ebenfalls als Bottom Sheets, und mobilePagination="load-more" (der Standard) hängt Zeilen an.

    tsx
    // components/clients.tsx
    "use client";
    import { Archive, Mail, Pencil } from "lucide-react";
    import { DataTable, createColumns } from "@/components/ui/data-table";
    type Client = { id: string; name: string; city: string; status: string; balance: number; owner: string; taxId: string };
    const col = createColumns<Client>();
    const columns = col([
    col.accessor("name", { header: "Kunde" }),
    col.accessor("city", { header: "Stadt", mobile: "subtitle", filter: "multi-select" }),
    col.accessor("status", {
    header: "Status",
    type: "badge",
    badge: { Aktiv: { tone: "success" }, Überfällig: { tone: "danger" } },
    filter: "multi-select",
    }),
    col.accessor("balance", { header: "Saldo", type: "currency" }),
    col.accessor("owner", { header: "Betreuer" }),
    col.accessor("taxId", { header: "Steuernummer", mobile: "hidden" }),
    ]);
    export function Clients({ clients }: { clients: Client[] }) {
    return (
    <DataTable
    data={clients}
    columns={columns}
    caption="Kunden"
    locale="en-US"
    selectionMode="multiple"
    bulkActions={(rows) => [
    { label: "E-Mail senden", icon: <Mail />, onSelect: () => console.log(rows.length) },
    { label: "Archivieren", icon: <Archive /> },
    ]}
    rowActions={(row) => [{ label: "Bearbeiten", icon: <Pencil />, onSelect: () => console.log(row.id) }]}
    />
    );
    }

    Den Rest erledigen hier die Standards: Kunde wird zum Titel, weil die Spalte als erste kommt, und Status wird zur Meta, weil es die erste Badge-Spalte ist. Saldo und Betreuer sind die Felder. Die Data Table zeigt höchstens vier Felder und lässt die übrigen auf der Karte weg, stell die wichtigen also nach vorn oder markiere den Rest bewusst als hidden.

    Auf dem Smartphone startet ein Long Press auf eine Kundenkarte die Auswahl, weitere Taps wählen mehr Karten aus, und die Leiste für Sammelaktionen schwebt unten. Auf einem breiten Screen ist es die volle Tabelle
    $ npx wingo-ui@latest add data-table
    ProDoku: Data Table

    Reicht die Zuordnung der Spalten nicht, nehmen beide Komponenten eine renderCard-Funktion für eine eigene Karte, und mobileLayout="scroll" nimmt eine einzelne Tabelle von den Karten aus.

    Was, wenn die Zeilen einfacher sind als eine Tabelle?

    Dann lass die Tabelle auf jeder Bildschirmgröße weg. Eine Liste von Teammitgliedern, Benachrichtigungen oder Einstellungen mit einem Namen, einer Detailzeile und einem Wert ist eine Liste, und die List gibt ihr Zeilen mit Avatar oder Icon, einem Wert am Ende, einem Zeilenmenü und Swipe-Aktionen auf Touch-Geräten (nach links wischen zum Archivieren oder Löschen, mit einem Sheet per Long Press als sichtbarer Alternative). Sie liest sich bei 390px und bei 1440px gut, ganz ohne Breakpoint.

    Wie testest du eine responsive Tabelle auf dem Smartphone?

    Prüf das, was am häufigsten kaputtgeht: Die Seite darf in Smartphone-Breite nie seitwärts scrollen. Ein Playwright-Test fängt das in der CI ab:

    ts
    // e2e/no-horizontal-scroll.spec.ts
    import { test, expect } from "@playwright/test";
    test.use({ viewport: { width: 390, height: 844 } });
    test("die Kundenseite passt auf ein Smartphone", async ({ page }) => {
    await page.goto("/clients");
    const overflow = await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth);
    expect(overflow).toBeLessThanOrEqual(0);
    await expect(page.getByRole("list", { name: "Kunden" })).toBeVisible();
    await expect(page.getByRole("table")).toBeHidden();
    });

    Ergänze einen Fall mit 360px für kleine Android-Smartphones und lass ihn in Light und Dark laufen. Mach danach einen Durchgang auf einem echten Smartphone: Long Press auf eine Karte, Zeilenmenü und Sortier-Control öffnen, und prüfen, dass die Leiste für Sammelaktionen über dem Home-Indikator sitzt.

    Wo fängst du am besten an?

    Nimm deine meistgenutzte Admin-Tabelle, gib jeder Spalte auf Papier eine Rolle und bau das Kartenlayout mit md:hidden neben die Tabelle. Willst du lieber mit Komponenten starten, die Zuordnung, Sortier-Chips, Auswahl per Long Press und die schwebende Leiste für Sammelaktionen schon mitbringen: Table und Data Table gehören zu Wingo UI Pro; füg eine mit npx wingo-ui@latest add data-table hinzu. Den Aufbau von Filtern und Server-Pagination auf TanStack Schritt für Schritt zeigt das Tutorial zur TanStack Table v9 Data Table (auf Englisch), und weitere Smartphone-Layouts findest du in Mobile UI in React.

    Komponenten in diesem Artikel

    • Data Table

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

      Pro
    • Table

      A React table component: semantic table parts plus a props API for small read-only tables that sort, total and turn into cards on phones.

      Pro
    • List

      A React list for settings, contacts, inboxes and orders: iOS grouped panels, selection, row menus, swipe actions and drag to reorder.

      Pro
    • Description List

      A React description list for detail pages: key-value grids for clients, invoices and profiles, with copy buttons, skeletons and iOS rows.

      Pro

    Häufige Fragen

    Wie mache ich eine Tabelle auf dem Smartphone responsive?

    Kläre zuerst, ob Leute Datensätze lesen oder Spalten vergleichen. Für Datensätze renderst du unter 768px eine Karte pro Zeile mit dem wichtigsten Feld als Titel und zwei bis vier beschrifteten Feldern; Vergleichsraster bleiben Tabellen, die in ihrer Box seitwärts scrollen, mit fixierter erster Spalte.

    Ist die shadcn Table auf dem Smartphone responsive?

    Sie scrollt. Die Table von shadcn/ui legt die Tabelle in ein div mit overflow-x-auto, eine breite Tabelle scrollt also seitwärts in ihrem Container. Zeilen in Karten zu verwandeln liegt bei dir, meist mit einem zweiten Markup-Zweig, den md:-Klassen ein- und ausblenden.

    Sollte ich display: block auf Tabellenzeilen setzen, um Karten zu bekommen?

    Optisch klappt das, und du hast nur eine Kopie des Markups, aber bis Safari 17 hat ein geändertes display auf Tabellenelementen in Safari die Tabellensemantik entfernt (Adrian Roselli, Oktober 2023), und display: contents kann weiterhin Probleme machen. Eine eigene Liste von Karten mit echten dt- und dd-Labels bekommst du für Screenreader leichter richtig hin.

    Wie sortieren Nutzer eine Tabelle auf dem Smartphone ohne Spaltenköpfe?

    Gib ihnen ein Control, das die Aufgabe der Spaltenköpfe übernimmt: eine Reihe von Chips „Sortieren nach“ über den Karten oder einen Sortieren-Button, der ein Bottom Sheet mit jeder Spalte auf- und absteigend öffnet.

    Sollte ich mit useIsMobile zwischen Tabelle und Karten wechseln?

    Nein. Ein Media-Query-Hook ist auf dem Server false, also rendern Smartphones zuerst die Tabelle und wechseln erst nach der Hydration zu den Karten. Render beide und blende eine mit md:hidden und hidden md:block aus, das stimmt schon beim ersten Paint.

    • Tabellen
    • Mobile
    • Responsive Design
    • React
    • Tailwind CSS

    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

    React Virtualized Table: 100.000 Zeilen mit TanStack Virtual

    Bau eine React Virtualized Table mit TanStack Virtual, die 100.000 Zeilen scrollt, den Header sticky hält und Fokus und Auswahl beim Unmounten nicht verliert.

    SRSerban Rusu·16. Okt. 2026·13 Min. Lesezeit
    Komponenten-Guides

    TanStack Table v9: Data Table mit Filtern und Bulk Actions

    Bau eine Admin-Datentabelle auf TanStack Table v9: tableFeatures, Spaltenfilter, Bulk Actions, Pinning mit start/end, Server-Pagination, Smartphone-Karten.

    SRSerban Rusu·9. Okt. 2026·12 Min. Lesezeit
    Mobile UI mit React

    React Swipe to Delete: iOS-Swipe-Actions mit Undo

    React Swipe to Delete für Listenzeilen: iOS-Swipe-Actions, ein Full Swipe zum Löschen, Undo per Toast und Buttons für alle mit Maus oder Tastatur.

    SRSerban Rusu·13. Okt. 2026·10 Min. Lesezeit
    Newsletter

    Neue Artikel per E-Mail

    Neue Guides, Tutorials und Vergleiche aus dem Wingo UI Blog, sobald sie erscheinen. Die meisten Artikel sind auf Englisch.

    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
    • Theme-Generator

    Ressourcen

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

    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