# TanStack Table: flexRender and the most common errors

flexRender takes a render function and the cell context. Errors come from a missing half, a renderer that returns an object, or a column not in the list.

> Page: https://ui.eneawork.it/blog/tanstack-table-flexrender-errore
> Markdown: https://ui.eneawork.it/blog/tanstack-table-flexrender-errore.md

*2026-11-01*

Risposta breve: flexRender riceve due argomenti, un renderer e il contesto della cella. Gli errori nascono quando manca uno dei due, quando il renderer restituisce un oggetto, o quando la colonna non è nella lista.

Il tag react conta 475.168 domande sulla Stack Exchange API al 31 ottobre 2026. TanStack Table non ha un tag dedicato nel dataset: la verifica utile è locale, sul codice della tabella. Il catalogo EneUI misura 111.985 componenti, 1.556 blocchi, 12.808 icone da 1.472 librerie, letti da /api/stats il 1 novembre 2026, e verificati con una chiamata diretta all'endpoint. Ogni comando qui sotto è eseguibile in locale: nessun passaggio richiede un account.

## Il meccanismo: due argomenti, nessuna magia

flexRender è una funzione di tre righe. Se il primo argomento è una funzione la chiama con il contesto; se è già un nodo React lo restituisce; se è una stringa o un numero lo lascia passare. Non controlla la colonna e non conosce la tabella.

La cella sa cosa mostrare perché la definizione di colonna glielo dice. Quando manca cell, il primo argomento arriva vuoto e la funzione restituisce null: React non protesta, la cella resta un rettangolo muto. Ecco perché il caso più frequente non produce un errore ma una colonna bianca.

import { flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"; const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel(), }); {table.getRowModel().rows.map((row) => ( {row.getVisibleCells().map((cell) => ( {flexRender(cell.column.columnDef.cell, cell.getContext())} ))} ))}

Le due chiavi sono obbligatorie: row.id e cell.id. Senza, React avvisa sulle key e il rendering può riusare la cella sbagliata dopo un riordino.

## Gli errori, uno per uno

Il secondo messaggio è quello che spaventa di più e si spiega in una riga: hai restituito row.original invece di un campo. React accetta testo e nodi, non oggetti. Stringa, numero o elemento: tutto il resto va estratto prima.

## Diagnosi: stampa il contratto delle colonne

Prima di leggere il DOM, guarda cosa contiene la definizione. Un log tabellare dice in un colpo quali colonne hanno un renderer, quali un accessor e quali nessuno dei due.

console.table( columns.map((c) => ({ id: c.id, accessor: "accessorKey" in c ? c.accessorKey : c.accessorFn ? "fn" : "display", cell: typeof c.cell, })), );

Se cell vale "undefined", il renderer non esiste. Se accessor vale "display", la colonna non legge nessun campo: è una colonna di sola azione, e va trattata come tale. Il terzo controllo è il nome del campo: un accessorKey che non esiste nei dati produce una cella vuota senza avvisi.

## Una cella con un componente

const columns: ColumnDef[] = [ { accessorKey: "id", header: "Ordine" }, { accessorKey: "status", header: "Stato", cell: ({ row }) => , }, ];

Il renderer è una funzione che riceve il contesto: flexRender la chiama e inserisce il risultato. Se scrivi cell: <StatusBadge />, passi un elemento invece di una funzione, e per la tabella quella colonna non ha un renderer chiamabile.

## Quando la correzione comune peggiora le cose

La prima reazione al re-render continuo è avvolgere tutto in useMemo con dipendenze vuote. Le colonne si congelano alla prima render: la tabella smette di rimbalzare e smette anche di aggiornare le etichette che dipendono da props, lingua, permessi, valuta. Il sintomo diventa «i filtri funzionano, le intestazioni no», che è più difficile da attribuire.

La seconda è cambiare le key per zittire l'avviso: key={index} o un valore casuale. Con le key instabili perdi lo stato di ogni cella, un input non controllato si svuota a ogni ordinamento, e React ricostruisce il DOM invece di riusarlo.

## Un limite da mettere in conto: non è un data grid

TanStack Table è headless: calcola righe e celle, non disegna niente. Non porta virtualizzazione, non porta aria-sort, non porta gestione del focus. Con qualche migliaio di righe il collo di bottiglia è il numero di nodi nel DOM, non flexRender: servono un virtualizzatore o la paginazione, e l'accessibilità della tabella resta lavoro tuo.

## Prevenzione

## Dove continuare

Nel catalogo: data table con preview, componenti e blocchi. Le guide: checklist accessibilità e alternative a MUI; il confronto: Radix, Base UI e React Aria.

## FAQ

### Perché `flexRender` restituisce undefined?

Perché il primo argomento non è una funzione: la colonna non dichiara `cell`, quindi non c'è nessun renderer da chiamare e non viene disegnato nulla.

### Come renderizzo un componente in una cella?

Definisci `cell: ({ row }) => ` e lascia che `flexRender` chiami la funzione con il contesto della cella.

### Devo chiamare `getRowModel()`?

Sì, è il metodo che produce le righe visibili. Senza, l'array è vuoto e la tabella mostra soltanto l'intestazione.

### Perché il rendering è lento con molte righe?

Perché stai renderizzando tutte le righe contemporaneamente. Serve virtualizzazione o paginazione: il rendering delle singole celle non è il collo di bottiglia.

### Le API cambiano tra le versioni?

Sì. Tra la v8 stabile e le alpha della v9 cambiano nomi e firme: fissa la versione nel package.json e leggi la documentazione di quella.
