<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Faizal Sukaimi]]></title><description><![CDATA[Faizal Sukaimi]]></description><link>https://faizalsukaimi.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Wed, 04 Nov 2026 01:53:04 GMT</lastBuildDate><atom:link href="https://faizalsukaimi.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[TanStack Table vs ReUI: picking a React data grid for a shadcn app]]></title><description><![CDATA[TanStack Table or ReUI? What each React data grid gives a shadcn app, and when to pick it.]]></description><link>https://faizalsukaimi.hashnode.dev/tanstack-table-vs-reui-picking-a-react-data-grid-for-a-shadcn-app</link><guid isPermaLink="true">https://faizalsukaimi.hashnode.dev/tanstack-table-vs-reui-picking-a-react-data-grid-for-a-shadcn-app</guid><category><![CDATA[React]]></category><category><![CDATA[webdev]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[shadcn]]></category><dc:creator><![CDATA[Faizal Sukaimi]]></dc:creator><pubDate>Mon, 02 Nov 2026 17:15:21 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ae19eca0db339e56cf0adb0/26cccd96-1348-4706-b905-64705325aacb.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you build a data grid with TanStack Table in a shadcn app, most of the work is the grid UI, not the table logic. ReUI's data grid is that UI already written, on top of the same TanStack Table. So the useful question isn't which engine to use. It's how much grid UI you want to write, and how much of it you want to own.</p>
<p>I work on ReUI, so keep that in mind. I'll point out where plain TanStack Table is the better call.</p>
<h2>What I checked</h2>
<p>I compared <code>@tanstack/react-table</code> 9.3.1 with the ReUI data grid as the shadcn CLI served it on 3 Nov 2026. To see exactly what lands in a project, I ran <code>npx shadcn@latest view @reui/data-grid</code> and counted the files.</p>
<table>
<thead>
<tr>
<th></th>
<th>TanStack Table</th>
<th>ReUI data grid</th>
</tr>
</thead>
<tbody><tr>
<td>What you install</td>
<td>one npm package</td>
<td>12 files in <code>components/reui/data-grid</code></td>
</tr>
<tr>
<td>UI included</td>
<td>none</td>
<td>table, header menus, filters, pagination, virtual table, cell selection</td>
</tr>
<tr>
<td>Extra packages</td>
<td>none</td>
<td>TanStack Virtual, dnd-kit, Base UI or Radix</td>
</tr>
<tr>
<td>Who maintains the UI</td>
<td>you</td>
<td>you, once it's installed</td>
</tr>
<tr>
<td>License</td>
<td>MIT</td>
<td>MIT, free</td>
</tr>
</tbody></table>
<h2>TanStack Table gives you state, not a table</h2>
<p>TanStack Table describes itself as headless, with "full control over markup, styles, and behavior". You get sorting, filtering, grouping, selection and pagination as state and row models. It renders nothing.</p>
<p>For a sortable, paged table that's ideal. You map rows into the shadcn <code>&lt;Table&gt;</code> you already have and you're done in an afternoon.</p>
<p>It gets heavier when the table has to behave like a grid: a menu on each column header, resize handles, pinned columns, keyboard focus moving between cells, virtualization (a separate package, TanStack Virtual), and copy and paste across a range of cells. TanStack Table leaves all of that UI to you on purpose.</p>
<h2>ReUI's data grid is that UI, already written</h2>
<pre><code class="language-bash">npx shadcn@latest add @reui/data-grid
</code></pre>
<p>That adds 12 files and a little over 11,000 lines of TSX to your project. The four biggest files:</p>
<table>
<thead>
<tr>
<th>File</th>
<th>Lines (about)</th>
<th>What it covers</th>
</tr>
</thead>
<tbody><tr>
<td><code>data-grid-table.tsx</code></td>
<td>3,100</td>
<td>the table, sticky headers, pinning, row states</td>
</tr>
<tr>
<td><code>data-grid-cell-selection.tsx</code></td>
<td>2,600</td>
<td>range selection, copy, paste, fill handle</td>
</tr>
<tr>
<td><code>data-grid.tsx</code></td>
<td>1,300</td>
<td>the provider and shared state</td>
</tr>
<tr>
<td><code>data-grid-table-virtual.tsx</code></td>
<td>1,200</td>
<td>row and column virtualization</td>
</tr>
</tbody></table>
<p>That number cuts both ways. It's a lot of grid work you skip. It's also a lot of code that now lives in your repo: you can change any line, and you also maintain every line.</p>
<p>One caveat on the cell selection file: a range selection you write yourself could be far smaller if you skip the edge cases (pinned columns, virtualized rows, translated labels). The count shows what a complete version covers, not what you'd have to write.</p>
<p>You still write the TanStack Table part. The grid renders it:</p>
<pre><code class="language-tsx">const table = useTable({
  features: dataGridFeatures,
  data,
  columns,
})

return (
  &lt;DataGrid table={table} recordCount={data.length}&gt;
    &lt;DataGridContainer&gt;
      &lt;DataGridTable /&gt;
    &lt;/DataGridContainer&gt;
    &lt;DataGridPagination /&gt;
  &lt;/DataGrid&gt;
)
</code></pre>
<p>Your columns, row models and state work the way they do in TanStack Table. Grid behaviour is turned on with <code>tableLayout</code> props instead of built by hand: <code>headerSticky</code>, <code>columnsResizable</code>, <code>columnsPinnable</code>, <code>columnsDraggable</code>, <code>rowsPinnable</code>, <code>cellSelection</code>. On top of that you get infinite scroll, tree and expandable rows, footer rows, inline editing, and one <code>i18n</code> prop for every built-in string.</p>
<p>Four of the free examples:</p>
<p><a href="https://reui.io/components/data-grid/c-data-grid-31?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=data-grid-comparison"><img src="https://reui.io/thumbnails/components/c-data-grid-31-dark.webp" alt="Spreadsheet editing" style="display:block;margin:0 auto" /></a></p>
<p><a href="https://reui.io/components/data-grid/c-data-grid-32?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=data-grid-comparison"><img src="https://reui.io/thumbnails/components/c-data-grid-32-dark.webp" alt="Column virtualization" style="display:block;margin:0 auto" /></a></p>
<p><a href="https://reui.io/components/data-grid/c-data-grid-18?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=data-grid-comparison"><img src="https://reui.io/thumbnails/components/c-data-grid-18-dark.webp" alt="Column controls" style="display:block;margin:0 auto" /></a></p>
<p><a href="https://reui.io/components/data-grid/c-data-grid-30?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=data-grid-comparison"><img src="https://reui.io/thumbnails/components/c-data-grid-30-dark.webp" alt="Tree rows" style="display:block;margin:0 auto" /></a></p>
<p>There are two versions, one on Base UI and one on Radix UI, so use the docs page that matches your project. What it doesn't have: pivot tables and Excel export.</p>
<h2>Which one I'd pick</h2>
<table>
<thead>
<tr>
<th>You need</th>
<th>Pick</th>
</tr>
</thead>
<tbody><tr>
<td>A sortable, paged table</td>
<td>TanStack Table with the shadcn <code>&lt;Table&gt;</code></td>
</tr>
<tr>
<td>Every pixel your own, and time to build it</td>
<td>TanStack Table</td>
</tr>
<tr>
<td>Pinning, resizing and virtualization in your own design system</td>
<td>ReUI data grid</td>
</tr>
<tr>
<td>Spreadsheet-style range selection and editing</td>
<td>ReUI data grid</td>
</tr>
</tbody></table>
<p>Docs and every example: <a href="https://reui.io/docs/components/base/data-grid?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=data-grid-comparison">https://reui.io/docs/components/base/data-grid?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=data-grid-comparison</a></p>
<p>If you've built a grid on TanStack Table, what took the longest: the column menus, virtualization, range selection, or something I didn't list?</p>
]]></content:encoded></item><item><title><![CDATA[Making a component library agent-ready: the ReUI MCP server]]></title><description><![CDATA[Coding agents invent props. The ReUI MCP server gives them the real shadcn/ui registry: search, real APIs, page plans and prop checks.]]></description><link>https://faizalsukaimi.hashnode.dev/making-a-component-library-agent-ready-the-reui-mcp-server</link><guid isPermaLink="true">https://faizalsukaimi.hashnode.dev/making-a-component-library-agent-ready-the-reui-mcp-server</guid><category><![CDATA[mcp]]></category><category><![CDATA[React]]></category><category><![CDATA[shadcn]]></category><category><![CDATA[AI]]></category><category><![CDATA[webdev]]></category><dc:creator><![CDATA[Faizal Sukaimi]]></dc:creator><pubDate>Wed, 28 Oct 2026 08:34:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/6ae19eca0db339e56cf0adb0/2e8027d3-34b5-4afe-aafb-4cd310d275be.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Coding agents are good at writing React. They are bad at knowing your component library. Ask one to "add a data grid with sorting" and it will happily invent a <code>sortable</code> prop that has never existed, or install a package name it made up. The code looks right and fails on the first render.</p>
<p>We hit this with ReUI, our set of components and blocks for shadcn/ui, so we built an MCP server that gives agents the real registry instead of their memory of it.</p>
<h2>What it does</h2>
<p>The ReUI MCP server runs at <code>https://mcp.reui.io</code> over Streamable HTTP, so any MCP-capable agent can use it. It does discovery and guidance only:</p>
<ul>
<li><strong>Find:</strong> search components, examples, blocks and icons in plain language.</li>
<li><strong>Read:</strong> return each component's real API inline, so the agent never has to scrape a docs page.</li>
<li><strong>Plan and validate:</strong> plan a whole page from an intent, and check planned props before any code is written.</li>
<li><strong>Install:</strong> return the exact shadcn CLI command for an item, after checking that it exists.</li>
</ul>
<p>It never serves source code. Installation stays with the shadcn CLI, which is also where a license key lives for premium items.</p>
<h2>Catching invented props before they ship</h2>
<p>The tool I like most is <code>validate_usage</code>. The agent sends the component and props it plans to use, and gets a verdict per prop, checked against the indexed API docs. No model, no guessing.</p>
<p>Here is a real call. The agent plans a data grid with <code>table</code>, <code>recordCount</code>, <code>isLoading</code> and <code>sortable</code>, and wants to install <code>c-data-grid-12</code> and <code>data-grid-pro</code>:</p>
<pre><code class="language-json">{
  "ok": false,
  "components": [{
    "name": "data-grid",
    "exists": true,
    "props": [
      { "prop": "table", "documented": true },
      { "prop": "recordCount", "documented": true },
      { "prop": "isLoading", "documented": true },
      { "prop": "sortable", "documented": false, "near": ["table", "sortingStrategy"] }
    ]
  }],
  "items": [
    { "name": "c-data-grid-12", "exists": true, "type": "example", "free": true },
    { "name": "data-grid-pro", "exists": false,
      "suggestions": [{ "name": "data-grid-advanced-7", "type": "block" }, { "name": "data-grid", "type": "component" }] }
  ]
}
</code></pre>
<p><code>sortable</code> was the invented prop, and <code>data-grid-pro</code> was the invented package. Both are caught before a single file changes, with a nudge toward what actually exists.</p>
<h2>Planning a page, not just a component</h2>
<p><code>compose_page</code> takes an intent like "SaaS billing settings page" and returns an ordered plan: an app shell, a settings block, a form, a dialog, each with a top pick, alternates, preview links and the install sequence. Pass <code>surface: "card"</code> and every section comes from the same design-system surface, so the page doesn't end up as a patchwork of styles.</p>
<p>The four picks from that run:</p>
<p><a href="https://reui.io/preview/base/app-shell-22?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=mcp-article"><img src="https://reui.io/thumbnails/blocks/app-shell-22-light.webp" alt="app-shell-22" style="display:block;margin:0 auto" /></a></p>
<p><a href="https://reui.io/preview/base/settings-7?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=mcp-article"><img src="https://reui.io/thumbnails/blocks/settings-7-light.webp" alt="settings-7" style="display:block;margin:0 auto" /></a></p>
<p><a href="https://reui.io/preview/base/form-5?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=mcp-article"><img src="https://reui.io/thumbnails/blocks/form-5-light.webp" alt="form-5" style="display:block;margin:0 auto" /></a></p>
<p><a href="https://reui.io/preview/base/dialog-10?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=mcp-article"><img src="https://reui.io/thumbnails/blocks/dialog-10-light.webp" alt="dialog-10" style="display:block;margin:0 auto" /></a></p>
<p>If a section has no good match, it is listed under <code>unavailableSections</code> instead of being filled with the closest wrong thing. That rule matters more than any ranking: an agent that admits a gap is easier to work with than one that papers over it.</p>
<h2>Setup</h2>
<p>Claude Code, from your project root:</p>
<pre><code class="language-bash">claude mcp add --transport http reui https://mcp.reui.io
</code></pre>
<p>Then run <code>/mcp</code>, pick <code>reui</code>, and approve the sign-in in your browser.</p>
<p>Cursor, in <code>.cursor/mcp.json</code>:</p>
<pre><code class="language-json">{
  "mcpServers": {
    "reui": { "url": "https://mcp.reui.io" }
  }
}
</code></pre>
<p>The first tool call opens a browser to sign in; a free account is created if you don't have one. For CI, create a personal token at Account → MCP and send it as <code>Authorization: Bearer reui_pat_...</code>.</p>
<p>A free account covers all the free components and <code>c-*</code> examples. A Pro license adds the premium blocks to search, page plans and installs.</p>
<h2>Pair it with the skill</h2>
<p>The server answers questions. The ReUI Agent Skill tells the agent which questions to ask, and in what order: plan, find, install, read the API, adapt by reuse, then check. Install it with:</p>
<pre><code class="language-bash">curl -fsSL https://mcp.reui.io/install | node -
</code></pre>
<p>In Claude Code it lands in <code>.claude/skills/reui</code> and adds <code>/mcp__reui__build</code>, <code>/mcp__reui__add</code>, <code>/mcp__reui__fix</code> and <code>/mcp__reui__improve</code>.</p>
<h2>Try it</h2>
<p>Docs and setup for other agents (VS Code, Gemini CLI and more): <a href="https://reui.io/docs/mcp?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=mcp-article">https://reui.io/docs/mcp?utm_source=hashnode&amp;utm_medium=social&amp;utm_campaign=mcp-article</a></p>
<p>I'd like to hear where it falls short for you, especially props it still lets through.</p>
]]></content:encoded></item></channel></rss>