<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Orwa Mahmoud</title>
    <description>The latest articles on DEV Community by Orwa Mahmoud (@orwamahmoud).</description>
    <link>https://dev.to/orwamahmoud</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4014610%2Fd1dc4c5c-ff84-4ec2-9a16-743c7759074d.jpg</url>
      <title>DEV Community: Orwa Mahmoud</title>
      <link>https://dev.to/orwamahmoud</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/orwamahmoud"/>
    <language>en</language>
    <item>
      <title>AdaptTable v3 is live: a framework-neutral engine, smaller feature imports, and optional AI</title>
      <dc:creator>Orwa Mahmoud</dc:creator>
      <pubDate>Sun, 20 Sep 2026 13:16:09 +0000</pubDate>
      <link>https://dev.to/orwamahmoud/adapttable-v3-is-live-a-framework-neutral-engine-smaller-feature-imports-and-optional-ai-2fgb</link>
      <guid>https://dev.to/orwamahmoud/adapttable-v3-is-live-a-framework-neutral-engine-smaller-feature-imports-and-optional-ai-2fgb</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/orwamahmoud/from-v1-to-v29-how-adapttable-grew-into-a-full-react-data-grid-toolkit-3pac"&gt;last AdaptTable update&lt;/a&gt;, I wrote about how much the project had grown by v2.9.&lt;/p&gt;

&lt;p&gt;By then, AdaptTable already had grouping, tree data, pivoting, editing, exports, virtualization, responsive layouts, and a lot more.&lt;/p&gt;

&lt;p&gt;That growth created a different problem.&lt;/p&gt;

&lt;p&gt;I didn't want every table to carry the weight of every feature, and I didn't want React itself to define the engine underneath the library.&lt;/p&gt;

&lt;p&gt;v3 is the release where I cleaned that up.&lt;/p&gt;

&lt;h2&gt;
  
  
  React is no longer the engine
&lt;/h2&gt;

&lt;p&gt;AdaptTable is still built for React developers today, and the same idea remains: use the UI kit already in your project instead of bringing in a table with a completely different look and feel.&lt;/p&gt;

&lt;p&gt;What changed is the architecture underneath it.&lt;/p&gt;

&lt;p&gt;Framework-neutral models and table operations now live in &lt;code&gt;@adapttable/core&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;React-specific hooks and subscriptions live in &lt;code&gt;@adapttable/react&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The adapters then handle the actual UI for Mantine, MUI, Chakra UI, Ant Design, Radix Themes, Base UI, shadcn/ui, and the unstyled/Tailwind route.&lt;/p&gt;

&lt;p&gt;Roughly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@adapttable/core
        ↓
@adapttable/react
        ↓
Mantine / MUI / Chakra / Ant / Radix / Base UI / shadcn / unstyled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The engine no longer needs to know how React subscribes to state, while the React layer only handles the React-specific binding around the table logic.&lt;/p&gt;

&lt;p&gt;It gives AdaptTable a cleaner foundation for other framework bindings later.&lt;/p&gt;

&lt;p&gt;Vue and Angular bindings are not part of v3. The engine is ready for that direction, but React is still the shipped framework binding today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional features are actually optional now
&lt;/h2&gt;

&lt;p&gt;v2 had already started moving features behind separate import paths.&lt;/p&gt;

&lt;p&gt;But there was still a problem.&lt;/p&gt;

&lt;p&gt;A feature can have its own public subpath and still end up in the main dependency graph if the root &lt;code&gt;DataTable&lt;/code&gt; imports its implementation internally.&lt;/p&gt;

&lt;p&gt;So an import can look modular without really being a bundle boundary.&lt;/p&gt;

&lt;p&gt;In v3, the old feature-enabling props are replaced by feature factories.&lt;/p&gt;

&lt;p&gt;A basic table can stay basic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataTable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;rowKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If that table needs grouping, it adds grouping:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataTable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;grouping&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine/grouping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;rowKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;grouping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;team&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The same approach is used for editing, virtualization, row reordering, column menus and other optional features.&lt;/p&gt;

&lt;p&gt;For applications that want the common controls together, there is still a convenient preset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;standardFeatures&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine/preset&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you can start with the preset for the common setup, or import individual features when you want a narrower table.&lt;/p&gt;

&lt;p&gt;In practice, the bundle cost follows the features your table actually uses.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI follows the same AdaptTable philosophy
&lt;/h2&gt;

&lt;p&gt;v3 also adds &lt;code&gt;@adapttable/ai&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I didn't want AI support to mean choosing a specific model provider, SDK or agent architecture just to use the table.&lt;/p&gt;

&lt;p&gt;The AI layer is separate from the normal table packages.&lt;/p&gt;

&lt;p&gt;A table exposes only the operations it actually supports. If editing is not enabled, the agent does not get editing tools. If a write needs approval or an application callback, it still has to go through that path.&lt;/p&gt;

&lt;p&gt;The application keeps control of authorization, validation, and persistence.&lt;/p&gt;

&lt;p&gt;There is a ready-made assistant UI, but it is optional. The same capabilities can also be connected to an existing chat interface or agent runtime.&lt;/p&gt;

&lt;p&gt;This follows the same idea as the UI adapters: AdaptTable should work with the stack already used by the application.&lt;/p&gt;

&lt;p&gt;AdaptTable has its own provider-neutral session and capability contract, and it also ships adapters for AI SDK and AG-UI, alongside integrations for OpenAI tools, MCP, and lower-level JSON.&lt;/p&gt;

&lt;p&gt;So an application can keep its existing provider, backend, and agent setup instead of rebuilding around AdaptTable.&lt;/p&gt;

&lt;p&gt;And like the rest of v3, AI is opt-in. If you never import the AI packages, the normal table does not depend on them.&lt;/p&gt;

&lt;p&gt;I'll cover capability discovery, revisions, approvals, execution results, and the boundary between the agent, table, and application in a separate post.&lt;/p&gt;

&lt;h2&gt;
  
  
  Moving from v2
&lt;/h2&gt;

&lt;p&gt;v3 is a major release, so there are breaking changes.&lt;/p&gt;

&lt;p&gt;React-specific hooks that previously came from &lt;code&gt;@adapttable/core&lt;/code&gt; move to &lt;code&gt;@adapttable/react&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The old feature-enabling props are replaced by feature factories.&lt;/p&gt;

&lt;p&gt;Deprecated routes and aliases that were being kept around for compatibility are removed.&lt;/p&gt;

&lt;p&gt;The CLI can help with supported import migrations, but I would still review application behavior after upgrading. A codemod can move an import; it can't decide how your application wants editing, persistence, or a custom feature to behave.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://orwa-mahmoud.github.io/adapttable/migrate-from-v2/" rel="noopener noreferrer"&gt;v2 → v3 migration guide&lt;/a&gt; covers the changes and replacements.&lt;/p&gt;

&lt;p&gt;AdaptTable remains MIT licensed.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://orwa-mahmoud.github.io/adapttable/demo/" rel="noopener noreferrer"&gt;try the live demo&lt;/a&gt;, &lt;a href="https://orwa-mahmoud.github.io/adapttable/" rel="noopener noreferrer"&gt;read the documentation&lt;/a&gt; or &lt;a href="https://github.com/orwa-mahmoud/adapttable" rel="noopener noreferrer"&gt;browse the source on GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>From v1 to v2.9: how AdaptTable grew into a full React data-grid toolkit</title>
      <dc:creator>Orwa Mahmoud</dc:creator>
      <pubDate>Thu, 03 Sep 2026 19:44:50 +0000</pubDate>
      <link>https://dev.to/orwamahmoud/from-v1-to-v29-how-adapttable-grew-into-a-full-react-data-grid-toolkit-3pac</link>
      <guid>https://dev.to/orwamahmoud/from-v1-to-v29-how-adapttable-grew-into-a-full-react-data-grid-toolkit-3pac</guid>
      <description>&lt;p&gt;Back in July I wrote the first post about &lt;a href="https://dev.to/orwamahmoud/one-headless-table-engine-every-react-ui-kit-2dm4"&gt;AdaptTable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The project was still v1, and the idea was fairly focused: one table engine that could sit behind the UI kit a React project already uses.&lt;/p&gt;

&lt;p&gt;MUI project? Use the MUI adapter.&lt;/p&gt;

&lt;p&gt;Mantine? Use Mantine.&lt;/p&gt;

&lt;p&gt;Ant Design, Chakra, Radix, shadcn, Base UI, or your own Tailwind styles all sit on the same engine too.&lt;/p&gt;

&lt;p&gt;That model is still there. The engine behind it has just grown a lot since then.&lt;/p&gt;

&lt;p&gt;The core is at v2.9 now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/orwa-mahmoud/adapttable" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; · &lt;a href="https://orwa-mahmoud.github.io/adapttable/demo/" rel="noopener noreferrer"&gt;Live demo&lt;/a&gt; · &lt;a href="https://orwa-mahmoud.github.io/adapttable/getting-started/" rel="noopener noreferrer"&gt;Getting started&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The feature set got much bigger
&lt;/h2&gt;

&lt;p&gt;The first release already covered the things I kept needing in application tables: sorting, filtering, pagination, URL state, saved views, column controls, server-side data, mobile layouts, selection, and row/card virtualization.&lt;/p&gt;

&lt;p&gt;Since then I've added quite a bit on top of that.&lt;/p&gt;

&lt;p&gt;Grouping now supports multiple levels and aggregates.&lt;/p&gt;

&lt;p&gt;There is tree data, pivot tables, formula/computed columns, and sparklines.&lt;/p&gt;

&lt;p&gt;The editing side grew a lot too.&lt;/p&gt;

&lt;p&gt;AdaptTable now has keyboard cell navigation, rectangular range selection, clipboard copy/paste, cut, fill handle behavior, and edit history.&lt;/p&gt;

&lt;p&gt;Editing can happen at cell level, row level, or as batched changes. There is validation, async validation, dirty-state tracking, and conflict handling for cases where live data changes while somebody is editing.&lt;/p&gt;

&lt;p&gt;Rows have more control now as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Row reordering&lt;/li&gt;
&lt;li&gt;Top and bottom row pinning&lt;/li&gt;
&lt;li&gt;Row and column spanning&lt;/li&gt;
&lt;li&gt;Full-width rows&lt;/li&gt;
&lt;li&gt;Custom row heights and styling&lt;/li&gt;
&lt;li&gt;Tree and nested structures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Export also moved beyond CSV and print, with XLSX and PDF support now available.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the feature API manageable
&lt;/h2&gt;

&lt;p&gt;As the feature set grew, I wanted a basic table to stay basic.&lt;/p&gt;

&lt;p&gt;A normal table can still look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;rowKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;v2 introduced a feature composition API for optional behavior.&lt;/p&gt;

&lt;p&gt;For example, row reordering can be added through its own entry point:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataTable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;rowReorder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine/row-reorder&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;rowKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;features&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;rowReorder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handleReorder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grouping, editing, virtualization, cell navigation, saved views, and other features follow the same direction.&lt;/p&gt;

&lt;p&gt;There is also a public &lt;code&gt;TableFeature&lt;/code&gt; API behind this. A feature can register its own editors, aggregators, commands, filters, menu items, panels, and other extensions through the same feature system.&lt;/p&gt;

&lt;p&gt;That gives me a cleaner way to keep expanding AdaptTable without turning every new capability into another permanent special case inside &lt;code&gt;DataTable&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some of the heavier code is already separate
&lt;/h2&gt;

&lt;p&gt;I also started splitting heavier capabilities into their own entry points instead of exporting everything from the main core package.&lt;/p&gt;

&lt;p&gt;Today the core has separate entries for things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@adapttable/core/xlsx
@adapttable/core/pdf
@adapttable/core/formula
@adapttable/core/pivot
@adapttable/core/stream
@adapttable/core/sparkline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those are outside the main core entry, so the application pays the bundle-size cost for those features only when it imports and uses them.&lt;/p&gt;

&lt;p&gt;The adapters have feature-specific entry points too. Mantine, for example, exposes paths such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@adapttable/mantine/row-reorder
@adapttable/mantine/grouping
@adapttable/mantine/editing
@adapttable/mantine/virtualize
@adapttable/mantine/cell-navigation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;v2 still keeps some optional feature implementations reachable from the main &lt;code&gt;DataTable&lt;/code&gt; import graph, so the adapter side doesn't get the full bundle-size benefit from those entry points yet.&lt;/p&gt;

&lt;p&gt;v3 will move those optional implementations out of the root import graph so applications only pay for the features they actually import and use.&lt;/p&gt;

&lt;p&gt;The deprecated v2 APIs will be removed at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The server side changed a lot too
&lt;/h2&gt;

&lt;p&gt;The original &lt;code&gt;TableSource&lt;/code&gt; idea is still there: the table can work with local data or with data controlled by a backend.&lt;/p&gt;

&lt;p&gt;That area has expanded quite a bit.&lt;/p&gt;

&lt;p&gt;There is now a separate &lt;a href="https://www.npmjs.com/package/@adapttable/server" rel="noopener noreferrer"&gt;&lt;code&gt;@adapttable/server&lt;/code&gt;&lt;/a&gt; package for parsing and validating AdaptTable query state on the server.&lt;/p&gt;

&lt;p&gt;Pagination, sorting, filters, filter trees, grouping, and pivot state can use the same table query model on both sides instead of needing a second representation just for the backend.&lt;/p&gt;

&lt;p&gt;Real-time updates are in now too.&lt;/p&gt;

&lt;p&gt;AdaptTable can consume row patches coming through WebSocket or SSE flows instead of reloading the entire dataset whenever something changes.&lt;/p&gt;

&lt;p&gt;The live-update work also connects with editing. A remote update can arrive while somebody is changing the same row locally, so those two parts of the table need to understand each other.&lt;/p&gt;

&lt;p&gt;There is support for SSR, React Server Components, and streaming as well.&lt;/p&gt;

&lt;p&gt;A lot of the work after v1 ended up happening around the data flow and lifecycle of the table, not only in the rendered grid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Eight adapters, one engine
&lt;/h2&gt;

&lt;p&gt;The public adapters today are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mantine&lt;/li&gt;
&lt;li&gt;MUI&lt;/li&gt;
&lt;li&gt;Chakra UI&lt;/li&gt;
&lt;li&gt;Ant Design&lt;/li&gt;
&lt;li&gt;Radix Themes&lt;/li&gt;
&lt;li&gt;Base UI&lt;/li&gt;
&lt;li&gt;shadcn/ui&lt;/li&gt;
&lt;li&gt;unstyled/Tailwind&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They all use the same underlying table state and feature logic while rendering with the components and conventions of their own UI stack.&lt;/p&gt;

&lt;p&gt;A Mantine project gets Mantine components. An MUI project gets MUI components. A project with its own design system can use the unstyled path.&lt;/p&gt;

&lt;p&gt;The core behavior stays shared across them.&lt;/p&gt;

&lt;p&gt;Everything is still MIT licensed.&lt;/p&gt;

&lt;h2&gt;
  
  
  v3 is next
&lt;/h2&gt;

&lt;p&gt;While working on v2, I kept running into one thing I want to fix properly in v3: too much of the engine is still tied to React.&lt;/p&gt;

&lt;p&gt;A lot of what AdaptTable does has nothing inherently React-specific about it.&lt;/p&gt;

&lt;p&gt;Sorting, filtering, grouping, pivots, formulas, query state, editing state, row models, and feature logic can all exist without React.&lt;/p&gt;

&lt;p&gt;For v3 I'm moving that logic into framework-neutral engine modules, with React hooks and components living in a separate binding layer.&lt;/p&gt;

&lt;p&gt;React will remain fully supported, but it won't define the architecture of the engine underneath it.&lt;/p&gt;

&lt;p&gt;That also opens the door to Vue and Angular integrations later without rebuilding the same table logic for each framework.&lt;/p&gt;

&lt;p&gt;v3 will also remove the deprecated v2 APIs and continue the bundle cleanup by moving optional feature implementations out of the root import graph.&lt;/p&gt;

&lt;p&gt;I'm also working on optional AI capabilities for v3.&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>typescript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I Stopped Treating Long AI Coding Runs Like Chats — Nightshift Now Treats Them Like Shifts</title>
      <dc:creator>Orwa Mahmoud</dc:creator>
      <pubDate>Wed, 02 Sep 2026 16:28:10 +0000</pubDate>
      <link>https://dev.to/orwamahmoud/i-stopped-treating-long-ai-coding-runs-like-chats-nightshift-now-treats-them-like-shifts-40ec</link>
      <guid>https://dev.to/orwamahmoud/i-stopped-treating-long-ai-coding-runs-like-chats-nightshift-now-treats-them-like-shifts-40ec</guid>
      <description>&lt;p&gt;A while ago I wrote about a problem I kept hitting with Claude Code: I could give it a large task, walk away, and come back later to find that it had stopped somewhere in the middle.&lt;/p&gt;

&lt;p&gt;That problem is what originally pushed me to build &lt;strong&gt;Nightshift&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;At first, the goal was mostly:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;How do I keep the agent working?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Once I got the agent to reliably work for hours, my focus shifted.&lt;/p&gt;

&lt;p&gt;The problem was no longer just keeping it alive. I started focusing on improving the &lt;strong&gt;shift itself&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;If I leave a coding agent working for several hours, how do I make that run something I can actually understand, trust, review, recover, and keep as history afterward?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That changed how I think about long-running agent work.&lt;/p&gt;

&lt;p&gt;I don't really want a six-hour conversation.&lt;/p&gt;

&lt;p&gt;I want a &lt;strong&gt;shift&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The shift should exist outside the chat
&lt;/h2&gt;

&lt;p&gt;The core idea in Nightshift is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The work contract and run state live on disk, not only in the conversation.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;During a shift, I want to be able to open the files and see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what is done&lt;/li&gt;
&lt;li&gt;what is being worked on now&lt;/li&gt;
&lt;li&gt;what is still open&lt;/li&gt;
&lt;li&gt;what is parked or blocked&lt;/li&gt;
&lt;li&gt;what decisions were made&lt;/li&gt;
&lt;li&gt;what was tried and rejected&lt;/li&gt;
&lt;li&gt;what still needs verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The conversation is still useful for instructions, reasoning, and following the work as it happens. But for a multi-hour shift, I don’t want it to be the only place that remembers what was agreed, what changed, what failed, and what is still left.&lt;/p&gt;

&lt;p&gt;That becomes especially important when context gets compacted, a session fails, or I come back the next morning and need to understand what happened without scrolling through one giant chat.&lt;/p&gt;




&lt;h2&gt;
  
  
  Two kinds of shifts
&lt;/h2&gt;

&lt;p&gt;Nightshift currently supports two main ways of working.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Planned shifts
&lt;/h3&gt;

&lt;p&gt;You define the work up front as a concrete feature plan.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] build the Products module&lt;/li&gt;
&lt;li&gt;[ ] add product categories&lt;/li&gt;
&lt;li&gt;[ ] add coupons and discount rules&lt;/li&gt;
&lt;li&gt;[ ] add inventory tracking&lt;/li&gt;
&lt;li&gt;[ ] add product search and filters&lt;/li&gt;
&lt;li&gt;[ ] audit the whole module end-to-end and make sure every backend flow has the required UI and works correctly&lt;/li&gt;
&lt;li&gt;[ ] add tests and verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each item can have its own quality or verification requirements, and/Or you can also define checks that apply to the whole shift.&lt;/p&gt;

&lt;p&gt;The shift keeps working until every contracted item is ticked off. Owner-defined quality checks describe what “done” should mean, but the model decides when an item is ready to tick. Nightshift tracks that state and mechanically prevents the model from clocking out while anything is still open. Whether the work is actually good enough is still for the human reviewer to decide.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Open-ended shifts
&lt;/h3&gt;

&lt;p&gt;This mode became one of my favorite parts of Nightshift.&lt;/p&gt;

&lt;p&gt;Instead of giving it a fixed checklist, I give it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;a goal + a strict time budget&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Improve this product for the next four hours.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent can inspect the product, codebase, history, tests, existing issues, comparable approaches, technical debt, UX problems, or other useful opportunities.&lt;/p&gt;

&lt;p&gt;It finds useful work, ranks it, works on the strongest opportunities, and then keeps going.&lt;/p&gt;

&lt;p&gt;If it finishes one thing early and tries to stop while meaningful time is still left, the shift pushes it to continue exploring and improving until the time budget is actually over.&lt;/p&gt;

&lt;p&gt;The stopping condition becomes less:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The model feels finished."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and more:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"The shift is over."&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  A side effect I ended up liking a lot
&lt;/h2&gt;

&lt;p&gt;This created a use case I didn't originally build Nightshift for.&lt;/p&gt;

&lt;p&gt;Sometimes my Claude, Codex, or Cursor usage is going to reset the next day, and I still have a chunk of allowance left.&lt;/p&gt;

&lt;p&gt;Maybe I don't have a feature prepared.&lt;/p&gt;

&lt;p&gt;Maybe nothing is currently planned on the timeline.&lt;/p&gt;

&lt;p&gt;Maybe I just have a few hours of usage that are going to disappear anyway.&lt;/p&gt;

&lt;p&gt;Instead of wasting that capacity, I can start an open-ended shift and say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You have three hours. Find useful work and improve the project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nightshift keeps the model working within that time budget instead of letting it finish one small task and stop after 20 minutes.&lt;/p&gt;

&lt;p&gt;So the ready-made and open-ended shifts also give me a way to &lt;strong&gt;spend otherwise-expiring usage usefully when I don't already have anything planned&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ready-made shifts
&lt;/h2&gt;

&lt;p&gt;You don't always need to design the shift yourself.&lt;/p&gt;

&lt;p&gt;Nightshift also has a catalog of reusable shifts for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;defect hunting&lt;/li&gt;
&lt;li&gt;test coverage&lt;/li&gt;
&lt;li&gt;quality debt&lt;/li&gt;
&lt;li&gt;dependency upgrades&lt;/li&gt;
&lt;li&gt;codebase review&lt;/li&gt;
&lt;li&gt;Product Evolution&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, Product Evolution is an open-ended shift that studies the product, its history, user needs, and relevant standards, ranks opportunities by evidence, value, effort, reversibility, and risk, then works on the strongest ones within the available time.&lt;/p&gt;

&lt;p&gt;The catalog is useful when I know I want to spend a few hours of agent time productively but don't have a detailed backlog ready.&lt;/p&gt;

&lt;p&gt;Longer term, I want this catalog to grow beyond my own workflows.&lt;/p&gt;

&lt;p&gt;If someone has a long-running workflow that consistently works well, it should be possible to turn that into a reusable shift that other people can install, customize, and contribute back.&lt;/p&gt;

&lt;p&gt;And I don't think those shifts necessarily need to be coding-only.&lt;/p&gt;

&lt;p&gt;Recurring workflows like SEO, research, audits, or other reviewable agent work can fit the same model too.&lt;/p&gt;




&lt;h2&gt;
  
  
  I didn't want to build another agent runtime
&lt;/h2&gt;

&lt;p&gt;This became an important design decision as Nightshift grew.&lt;/p&gt;

&lt;p&gt;I don't want Nightshift to replace Claude Code, Codex, or Cursor.&lt;/p&gt;

&lt;p&gt;Those tools already have their own ecosystems, commands, skills, hooks, capabilities, and ways of working.&lt;/p&gt;

&lt;p&gt;Nightshift is designed to &lt;strong&gt;augment those ecosystems&lt;/strong&gt;, not sit in front of them as another agent platform.&lt;/p&gt;

&lt;p&gt;There is no Nightshift cloud service or account.&lt;/p&gt;

&lt;p&gt;You don't need another npm CLI or Homebrew-installed orchestration runtime that proxies the agent.&lt;/p&gt;

&lt;p&gt;Claude Code should still feel like Claude Code.&lt;/p&gt;

&lt;p&gt;Codex should still feel like Codex.&lt;/p&gt;

&lt;p&gt;Cursor should still feel like Cursor.&lt;/p&gt;

&lt;p&gt;Nightshift adds the &lt;strong&gt;shift contract, state, enforcement, recovery, review, and archive layer&lt;/strong&gt; around them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Long-running doesn't just mean "keep looping"
&lt;/h2&gt;

&lt;p&gt;There are already good ideas for keeping agents working for a long time.&lt;/p&gt;

&lt;p&gt;Ralph-style loops, for example, already established patterns around persistent plans, specs, repeated iterations, and state that survives outside a single chat.&lt;/p&gt;

&lt;p&gt;So Nightshift isn't trying to claim that file-backed plans or long-running loops are new.&lt;/p&gt;

&lt;p&gt;The part I'm interested in is the accountability around the run:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what exactly was contracted&lt;/li&gt;
&lt;li&gt;what is still unfinished&lt;/li&gt;
&lt;li&gt;what quality bar applies&lt;/li&gt;
&lt;li&gt;what decisions were made&lt;/li&gt;
&lt;li&gt;what got blocked&lt;/li&gt;
&lt;li&gt;what failed&lt;/li&gt;
&lt;li&gt;what was verified&lt;/li&gt;
&lt;li&gt;whether the session died&lt;/li&gt;
&lt;li&gt;how it recovered&lt;/li&gt;
&lt;li&gt;what evidence exists afterward&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keeping an agent running for six hours is useful.&lt;/p&gt;

&lt;p&gt;Being able to understand &lt;strong&gt;what actually happened during those six hours&lt;/strong&gt; is much more useful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Recovery should survive the agent itself
&lt;/h2&gt;

&lt;p&gt;Another part I didn't want to trust only to prompting was recovery.&lt;/p&gt;

&lt;p&gt;If the process doing the work is also the only thing responsible for noticing that it died, that isn't very helpful.&lt;/p&gt;

&lt;p&gt;Nightshift therefore has an external watchman.&lt;/p&gt;

&lt;p&gt;For example, if a Claude Code session hits a structured API failure such as:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;API Error: 500&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;the watchman can keep attempting to recover the recorded conversation when the API becomes available again.&lt;/p&gt;

&lt;p&gt;For Codex, the watchman can recover a session once it is proven dead, preferring the recorded session when its identity is resumable. If that isn't possible, the on-disk contract still provides the handoff for a fresh recovery.&lt;/p&gt;

&lt;p&gt;Failures will happen.&lt;/p&gt;

&lt;p&gt;The goal isn't to pretend they won't.&lt;/p&gt;

&lt;p&gt;The goal is that a temporary API or session failure doesn't silently throw away the remaining hours of work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The shift doesn't disappear when it ends
&lt;/h2&gt;

&lt;p&gt;This is one of the parts I appreciate more the longer I use Nightshift.&lt;/p&gt;

&lt;p&gt;When I want to file away finished work, Nightshift can archive the completed part of the shift.&lt;/p&gt;

&lt;p&gt;Nightshift moves completed items, handled snags, and the rotated journal into a dated archive. Receipts are copied into the dated archive too, while the live copies stay in place.&lt;/p&gt;

&lt;p&gt;The active contract and any still-open work stay intact instead of being filed away as if they were finished.&lt;/p&gt;

&lt;p&gt;Over time, those dated archives become a much cleaner history of previous shifts.&lt;/p&gt;

&lt;p&gt;The original conversation might be thousands of lines long, but the archive gives me a short, structured record of what was completed, what decisions were made, what went wrong, and what evidence was left behind.&lt;/p&gt;

&lt;p&gt;So instead of reopening an old marathon chat and trying to reconstruct what happened, I can open the archive for that date and understand the shift much faster.&lt;/p&gt;

&lt;p&gt;Even a shift I decide not to merge can leave useful history.&lt;/p&gt;

&lt;p&gt;Maybe the implementation wasn't good enough, but the investigation found something important.&lt;/p&gt;

&lt;p&gt;Maybe an approach failed, and I don't want the next agent rediscovering the same dead end.&lt;/p&gt;

&lt;p&gt;Maybe a decision needs to be revisited later.&lt;/p&gt;

&lt;p&gt;That history is worth keeping.&lt;/p&gt;




&lt;h2&gt;
  
  
  Read the receipts, not the promise
&lt;/h2&gt;

&lt;p&gt;The direction I'm pushing Nightshift toward is pretty simple.&lt;/p&gt;

&lt;p&gt;I don't want the final handoff to just be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Done! Everything looks good."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I want to be able to inspect the actual state, diff, commits, verification, decisions, failures, and receipts myself.&lt;/p&gt;

&lt;p&gt;Long-running autonomy becomes easier to trust when you don't have to trust the agent's summary of its own work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Read the receipts, not the promise.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Nightshift is now
&lt;/h2&gt;

&lt;p&gt;Nightshift is open source under MIT and currently supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Claude Code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OpenAI Codex&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs locally and is designed to augment those tools rather than replace them.&lt;/p&gt;

&lt;p&gt;The project is still evolving, especially around reusable shifts, stronger review workflows, and making the same model useful beyond coding.&lt;/p&gt;

&lt;p&gt;But the basic idea has become pretty clear to me:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Give the agent a real shift instead of one enormous chat.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Define the work or the time budget.&lt;/p&gt;

&lt;p&gt;Keep the state outside the conversation.&lt;/p&gt;

&lt;p&gt;Keep it working while the shift is active.&lt;/p&gt;

&lt;p&gt;Recover when things fail.&lt;/p&gt;

&lt;p&gt;Keep the evidence.&lt;/p&gt;

&lt;p&gt;Archive the result.&lt;/p&gt;

&lt;p&gt;Then review what actually happened.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nightshift
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/orwa-mahmoud/nightshift" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chatgpt.com/plugins/plugins_6a7c58f65d708191b3a705a8625baffe" rel="noopener noreferrer"&gt;Official OpenAI Plugin Directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nightshift.orwamahmoud.com/" rel="noopener noreferrer"&gt;Website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're already leaving coding agents working unattended for hours, I'd be especially interested in the workflows you've found that consistently work well.&lt;/p&gt;

&lt;p&gt;Some of them might make good reusable Nightshift shifts.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>agents</category>
      <category>agentskills</category>
    </item>
    <item>
      <title>Why Claude Code Stops Halfway Through Long Tasks—and the Harness I Built to Keep It Moving</title>
      <dc:creator>Orwa Mahmoud</dc:creator>
      <pubDate>Tue, 28 Jul 2026 17:08:23 +0000</pubDate>
      <link>https://dev.to/orwamahmoud/why-claude-code-stops-halfway-through-long-tasks-and-the-harness-i-built-to-keep-it-moving-532o</link>
      <guid>https://dev.to/orwamahmoud/why-claude-code-stops-halfway-through-long-tasks-and-the-harness-i-built-to-keep-it-moving-532o</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjc2bl73x5utii8linn8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjc2bl73x5utii8linn8g.png" alt=" " width="800" height="791"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I kept giving Claude Code long task lists, stepping away, and coming back to find it had completed the easy parts and stopped before the difficult ones.&lt;/p&gt;

&lt;p&gt;Sometimes it was worse.&lt;/p&gt;

&lt;p&gt;Claude would work until 2 AM, ask one non-critical question, and then sit idle for six hours until I woke up at 8.&lt;/p&gt;

&lt;p&gt;The question was usually reasonable, but it was not truly blocking. Claude could have chosen a safe default, continued working, and left the decision for me to review later.&lt;/p&gt;

&lt;p&gt;That is a harness problem, not only a model problem. The layer around the agent loop decides what “done” means, when the run may stop, and what happens when human input is unavailable.&lt;/p&gt;

&lt;p&gt;That problem led me to create &lt;strong&gt;Nightshift&lt;/strong&gt;, an open-source reliability harness plugin for long unattended Claude Code sessions.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Update (v0.6, July 2026): the night the API died&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since publishing this, the &lt;em&gt;other&lt;/em&gt; overnight killer got its fix. Claude had elevated errors across multiple models one evening — &lt;code&gt;API Error: 500&lt;/code&gt;, &lt;code&gt;529 Overloaded&lt;/code&gt; — right as I was about to start an overnight run. That is the failure no prompt can fix: once a session dies on an API error, nothing inside it can restart it. And I was not going to sit up watching status.claude.com.&lt;/p&gt;

&lt;p&gt;nightshift now ships a &lt;strong&gt;night watchman&lt;/strong&gt; — a small process outside the session that wakes every 10 minutes and reads only the session's own signals: its transcript, its recorded process, Claude Code's session roster. A session that died — or one wedged with an API error as the transcript's last word — gets &lt;code&gt;claude --resume&lt;/code&gt; fired into the &lt;strong&gt;same conversation&lt;/strong&gt;, and the watchman keeps knocking until the API answers. Esc or Ctrl-C always wins: it revives the endings nobody chose, never the ones you did. In the morning the whole night is one thread — the error, the revival, the finished work — with a direct link back to it.&lt;/p&gt;

&lt;p&gt;Full details: &lt;a href="https://nightshift.orwamahmoud.com/" rel="noopener noreferrer"&gt;the nightshift site&lt;/a&gt; · &lt;a href="https://github.com/orwa-mahmoud/nightshift" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Keeping the task outside the conversation
&lt;/h2&gt;

&lt;p&gt;Nightshift uses a persistent Markdown punch list as the source of truth.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Nightshift Punch List&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; [ ] Add rate limiting
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add tests for failed login attempts
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Update the API documentation
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Run the full test suite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Claude works through the list one item at a time.&lt;/p&gt;

&lt;p&gt;Because the work is stored in a file rather than only inside the current context window, the session can recover after context compaction, interruption, or restart.&lt;/p&gt;
&lt;h2&gt;
  
  
  Preventing quiet early exits
&lt;/h2&gt;

&lt;p&gt;Nightshift includes a stop hook that checks the punch list whenever Claude tries to finish.&lt;/p&gt;

&lt;p&gt;If unchecked items remain, the normal stop is blocked and Claude is instructed to continue.&lt;/p&gt;

&lt;p&gt;The shift ends only when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every item is completed&lt;/li&gt;
&lt;li&gt;the deadline is reached&lt;/li&gt;
&lt;li&gt;an optional stall limit is reached&lt;/li&gt;
&lt;li&gt;or the owner explicitly stops it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If no stall limit is configured, stalled work stays held and visibly flagged rather than quietly clocking out.&lt;/p&gt;

&lt;p&gt;This is stronger than simply prompting Claude to “continue until finished” because the completion condition is checked against persistent state.&lt;/p&gt;
&lt;h2&gt;
  
  
  Non-blocking questions should not stop the night
&lt;/h2&gt;

&lt;p&gt;Most human-in-the-loop systems pause the agent whenever it has a question.&lt;/p&gt;

&lt;p&gt;That makes sense for destructive or high-risk decisions. It does not make sense for every naming choice, implementation preference, or reversible decision.&lt;/p&gt;

&lt;p&gt;During a Nightshift session, non-blocking questions are parked with the default Claude chose.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Parking Lot&lt;/span&gt;
&lt;span class="p"&gt;
-&lt;/span&gt; Question: Should the endpoint return 200 or 201?
&lt;span class="p"&gt;-&lt;/span&gt; Default used: 201, matching the existing creation endpoints.
&lt;span class="p"&gt;-&lt;/span&gt; Review later: Confirm API consistency.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Claude continues working, and the developer reviews those decisions in the morning.&lt;/p&gt;

&lt;p&gt;The goal is not to remove human oversight. It is to make some of that oversight asynchronous instead of forcing the whole session to wait.&lt;/p&gt;
&lt;h2&gt;
  
  
  Guardrails for unattended work
&lt;/h2&gt;

&lt;p&gt;Long-running autonomy needs clear boundaries.&lt;/p&gt;

&lt;p&gt;Nightshift can mechanically enforce restrictions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;blocking &lt;code&gt;git push&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;denying dangerous commands&lt;/li&gt;
&lt;li&gt;protecting selected directories&lt;/li&gt;
&lt;li&gt;checking diffs for secret-like content&lt;/li&gt;
&lt;li&gt;enforcing a specific Git identity&lt;/li&gt;
&lt;li&gt;preventing non-blocking questions from pausing the shift&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A prompt saying “do not push” is helpful.&lt;/p&gt;

&lt;p&gt;A hook that rejects &lt;code&gt;git push&lt;/code&gt; is stronger.&lt;/p&gt;

&lt;p&gt;These guardrails are not a security sandbox, but they reduce the risk of relying only on the model to remember every instruction.&lt;/p&gt;
&lt;h2&gt;
  
  
  Verification before completion
&lt;/h2&gt;

&lt;p&gt;A checked box is still a claim made by the agent.&lt;/p&gt;

&lt;p&gt;Nightshift cannot guarantee that the implementation is correct or replace code review. What it can do is enforce a more disciplined workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;implement the change&lt;/li&gt;
&lt;li&gt;run the relevant verification&lt;/li&gt;
&lt;li&gt;inspect the result&lt;/li&gt;
&lt;li&gt;commit the completed item&lt;/li&gt;
&lt;li&gt;mark the checkbox complete&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Verification can include commands such as:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test
&lt;/span&gt;npm run lint
npm run typecheck
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nightshift also encourages one commit per completed item, making the run easier to inspect or partially revert.&lt;/p&gt;
&lt;h2&gt;
  
  
  Resumability and receipts
&lt;/h2&gt;

&lt;p&gt;Nightshift stores operational state inside &lt;code&gt;.nightshift/&lt;/code&gt;, including punch lists, parked questions, logs, deadlines, stop signals, and completion snapshots.&lt;/p&gt;

&lt;p&gt;This state can have its own local Git history, separate from the main project repository.&lt;/p&gt;

&lt;p&gt;That gives the developer two different records:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;project commits showing what changed&lt;/li&gt;
&lt;li&gt;Nightshift receipts showing what happened during the run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the session is interrupted, a new session can inspect the same state and continue from the remaining work.&lt;/p&gt;
&lt;h2&gt;
  
  
  What Nightshift does not solve
&lt;/h2&gt;

&lt;p&gt;Nightshift does not eliminate hallucinations.&lt;/p&gt;

&lt;p&gt;It does not guarantee that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every completed item is actually correct&lt;/li&gt;
&lt;li&gt;tests cover every requirement&lt;/li&gt;
&lt;li&gt;every chosen default is good&lt;/li&gt;
&lt;li&gt;every unsafe command will be detected&lt;/li&gt;
&lt;li&gt;a poorly written task list will produce a good result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It adds persistence, constraints, verification habits, resumability, and visibility around Claude Code.&lt;/p&gt;

&lt;p&gt;Human review is still required.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Inside Claude Code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/plugin marketplace add orwa-mahmoud/nightshift
/plugin install nightshift
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Then initialize it inside your project:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/nightshift:setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Review the generated punch list and start the shift:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/nightshift:start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Overview and FAQ:&lt;/p&gt;


&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://nightshift.orwamahmoud.com/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnightshift.orwamahmoud.com%2Fog.jpg" height="400" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://nightshift.orwamahmoud.com/" rel="noopener noreferrer" class="c-link"&gt;
            Nightshift — Accountable autonomous engineering shifts
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            Give coding agents a durable punch list, safety rules, recovery, and a reviewable morning handoff.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fnightshift.orwamahmoud.com%2Fnightshift-logo.png" width="512" height="512"&gt;
          nightshift.orwamahmoud.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;



&lt;p&gt;Nightshift is free, open source, and MIT licensed.&lt;/p&gt;

&lt;p&gt;Contributions, issues, and feedback are welcome:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/orwa-mahmoud/nightshift" rel="noopener noreferrer"&gt;https://github.com/orwa-mahmoud/nightshift&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>opensource</category>
      <category>claude</category>
      <category>devtools</category>
    </item>
    <item>
      <title>One headless table engine, every React UI kit</title>
      <dc:creator>Orwa Mahmoud</dc:creator>
      <pubDate>Sat, 04 Jul 2026 08:06:43 +0000</pubDate>
      <link>https://dev.to/orwamahmoud/one-headless-table-engine-every-react-ui-kit-2dm4</link>
      <guid>https://dev.to/orwamahmoud/one-headless-table-engine-every-react-ui-kit-2dm4</guid>
      <description>&lt;p&gt;Every React project reaches for a data table eventually, and the choice always feels like a trap:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reach for &lt;strong&gt;ag-Grid&lt;/strong&gt; or &lt;strong&gt;MUI X DataGrid&lt;/strong&gt; and you get power — but their look, their DOM, and (for the good features) their license.&lt;/li&gt;
&lt;li&gt;Reach for &lt;strong&gt;TanStack Table&lt;/strong&gt; and you get total freedom — but now &lt;em&gt;you&lt;/em&gt; build every cell, header, filter, and pagination control from scratch.&lt;/li&gt;
&lt;li&gt;Reach for a kit-specific table (Mantine, Chakra, Ant) and you're locked to that one kit, re-learning a new API each time.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted one table that renders &lt;strong&gt;natively&lt;/strong&gt; in whatever UI kit a project already uses, with the same features everywhere, and a headless escape hatch when the defaults aren't enough. So I built &lt;strong&gt;AdaptTable&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One API, real native components
&lt;/h2&gt;

&lt;p&gt;The whole table is five lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DataTable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useFrontendData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;ColumnDef&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adapttable/mantine&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColumnDef&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sortable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;accessor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;People&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;source&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useFrontendData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;DataTable&lt;/span&gt; &lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;source&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;rowKey&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Swap the import for &lt;code&gt;@adapttable/mui&lt;/code&gt;, &lt;code&gt;@adapttable/chakra&lt;/code&gt;, &lt;code&gt;@adapttable/antd&lt;/code&gt;, &lt;code&gt;@adapttable/radix&lt;/code&gt;, &lt;code&gt;@adapttable/shadcn&lt;/code&gt;, or &lt;code&gt;@adapttable/unstyled&lt;/code&gt; — same props, different kit.&lt;/p&gt;

&lt;p&gt;The key part: it is &lt;strong&gt;not&lt;/strong&gt; a wrapper that looks the same everywhere. Each adapter renders that kit's &lt;em&gt;actual&lt;/em&gt; components — MUI gets Material elevation, Ant gets Ant's compact density, Chakra gets Chakra's tokens. Same behavior, native skin. Flip the switcher in the live demo and watch one dataset re-render through each kit: &lt;a href="https://orwa-mahmoud.github.io/adapttable/demo/" rel="noopener noreferrer"&gt;https://orwa-mahmoud.github.io/adapttable/demo/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Filters and state that live in the URL
&lt;/h2&gt;

&lt;p&gt;My favorite part: open the filter drawer, set a status and a date range, copy the link — whoever opens it sees the exact same view. Search, filters, sort, and page all serialize into query params (&lt;code&gt;q&lt;/code&gt;, &lt;code&gt;page&lt;/code&gt;, &lt;code&gt;f_status&lt;/code&gt;, …), so every view is refresh-safe, back/forward-safe, and shareable. No &lt;code&gt;useState&lt;/code&gt; juggling, no wiring: declare the filters and the URL sync comes with them, identically for client-side data and server-side fetching (there's a router adapter for Next.js and react-router).&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get for free
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Sorting, filtering (with removable chips), global search&lt;/li&gt;
&lt;li&gt;Row selection + bulk actions&lt;/li&gt;
&lt;li&gt;Column management — show/hide, reorder, pin (sticky), resize&lt;/li&gt;
&lt;li&gt;Pagination — numbered or infinite scroll, auto by device&lt;/li&gt;
&lt;li&gt;Shareable URL state + saved views&lt;/li&gt;
&lt;li&gt;First-class RTL / Arabic and dark mode&lt;/li&gt;
&lt;li&gt;Optional virtualization — a 10k-row list mounts ~24 DOM rows&lt;/li&gt;
&lt;li&gt;Client-side data &lt;em&gt;and&lt;/em&gt; server-side (you supply the fetch) through one contract&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Headless when you need it
&lt;/h2&gt;

&lt;p&gt;Under every adapter is &lt;code&gt;@adapttable/core&lt;/code&gt; — a headless engine with prop-getters (&lt;code&gt;getTableProps&lt;/code&gt;, &lt;code&gt;getRowProps&lt;/code&gt;, …). If the batteries-included adapter isn't enough, drop down and render your own markup on the same engine. You never hit a wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it's not
&lt;/h2&gt;

&lt;p&gt;No pivoting, grouping, or Excel-style editing yet— this is for the CRUD tables most apps ship, not analytics grids. If you need those, ag-Grid is the right tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Try it in your browser (no install): &lt;a href="https://stackblitz.com/github/orwa-mahmoud/adapttable/tree/main/starters/mantine" rel="noopener noreferrer"&gt;https://stackblitz.com/github/orwa-mahmoud/adapttable/tree/main/starters/mantine&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live demo (flip the kit switcher): &lt;a href="https://orwa-mahmoud.github.io/adapttable/demo/" rel="noopener noreferrer"&gt;https://orwa-mahmoud.github.io/adapttable/demo/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Docs: &lt;a href="https://orwa-mahmoud.github.io/adapttable/getting-started/" rel="noopener noreferrer"&gt;https://orwa-mahmoud.github.io/adapttable/getting-started/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npx @adapttable/cli init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;MIT, stable v1 (1.1 just brought every adapter to full feature parity): &lt;a href="https://github.com/orwa-mahmoud/adapttable" rel="noopener noreferrer"&gt;https://github.com/orwa-mahmoud/adapttable&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback very welcome — especially whether the per-kit rendering holds up in your stack, and how the declarative API feels next to what you use today.&lt;/p&gt;

</description>
      <category>react</category>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
