Skip to content

Public beta · Open source

Admin panels for Laravel, written in PHP. Rendered in React.

Describe pages, tables, forms and actions in a PHP DSL; Tabletop renders them as a React admin. We build every client project on it, and our own CMS — closed beta today, public next.

composer require tbtop/admin

MIT licenceLaravel 11–13PHP 8.4+Self-hosted

yourapp.test/admin/dashboard
yourapp.test/admin/pages/1/edit
yourapp.test/admin/pages
The pages list: title, type, status and SEO badges, with filter tabs above
[01]Why another admin builder

Two ways to build an admin. Both end the same way.

Every team that ships a Laravel product hits this choice. Tabletop exists because we hit it twice.

  • The ready-made admin

    Fast first release. Then overrides, vendor patches and a UI runtime that still thinks your product is a set of resources.

    Then

    You fight the tool to reach your product.

  • The hand-written React admin

    Total freedom. Then you rebuild tables, forms, validation, permissions and loading states — and drift away from Laravel.

    Then

    You rebuild the tool to reach your product.

  • Tabletop

    Author in PHP like the first. Render and extend in React like the second. Laravel stays the owner of models, policies, queues and validation.

    Then

    You describe the product. The tool stays out of the way.

[02]How it works

You describe the screen. The client renders it.

A page is a PHP class. It serializes to a typed JSON contract, and the React client renders that contract over Inertia — the same runtime that draws every screen in our CMS. Laravel keeps the backend: models, policies, queues and validation.

tbtop/cms@bf0ce9a · src/Admin/Pages/Support/DashboardStats.php
public static function cards(S $s, bool $showSubmissions = true): array{    return array_values(array_filter([        self::pagesCard($s),        $showSubmissions ? self::submissionsCard($s) : null,        self::mediaCard($s),        self::layoutsCard($s),    ]));} private static function pagesCard(S $s): Stat{    return $s->stat('Pages')        ->value($published + $draft)        ->icon('file-text')        ->sparkline(self::dailyCounts(Page::query()), 'bottom');}
yourapp.test/admin/dashboard
The CMS dashboard: stat cards for pages, submissions, media and layouts, each with a trend line, above the submission charts
  1. 01 — Author

    Write the page in PHP.

    A Filament-shaped DSL. Pages, tables, forms and actions, per request.

    $s->table('posts')->columns([...])
  2. 02 — Serialize

    One wire contract.

    PHP emits JSON. A schema guards it. Both sides are checked against one fixture.

    { "kind": "table", "name": "posts" }
  3. 03 — Render

    React draws the screen.

    26 field kinds (richtext with embedded blocks among them), your own components, effects that drive the UI.

    registerBlock('rating', RatingField)
[03]From a prototype to a platform

Built after the prototype became a product.

Every layer of Tabletop exists because a real project eventually demanded it. The line continues into what we are building next.

  1. A ready-made admin

    Our first products shipped in weeks on a ready-made Laravel admin. It was the right tool for a first release.

  2. The ceiling

    The products grew and every screen got more specific. Soon most of the work went into bending the admin, not into features.

  3. A React admin from scratch

    Live previews, custom fields, real UI state. And a second codebase, drifting away from the Laravel app that already owned the models, auth and validation.

  4. AvailableBeta

    Tabletop

    The synthesis: PHP-first authoring, a React runtime, Laravel as the owner of both.

  5. In progressBeta

    Today: the builder, with a CMS in closed beta

    tbtop/admin is public and MIT on GitHub. Every tbtop/cms screen, from pages and blocks to revisions, scheduling and SEO, is ordinary builder DSL.

    See the CMS
    yourapp.test/admin/pages/1/edit
    Today: the builder, with a CMS in closed beta
  6. In progress

    Next: tbtop/admin 1.0 and the CMS public beta

    Planned together for the end of 2026: a frozen contract with semver for the builder, and the CMS open to everyone.

  7. Planned

    Then: CRM

    Contacts, deals and pipelines on the same builder, in 2027.

Roadmap, not a promise: order and scope change with real projects.as of October 2026

Full roadmap
[04]What you get

Things you'd otherwise build yourself. Built in, not bolted on.

Ten things the builder carries so your team does not have to write them, or go looking for a plugin on the second day.

  • A typed contract with a drift guard

    PHP and React share one schema. Contract tests catch it when the two sides disagree.

    The two sides can't drift apart silently.

  • Validation written once

    The declarative subset of your Laravel rules ships to the client for on-blur checks. The server stays the only boundary.

    No second copy of the rules in JavaScript.

  • Your React component is a first-class citizen

    A custom field, widget or page is one React component you use from PHP by name.

    Extend without forking the package.

  • Totals and previews as you type

    A component reads the unsaved form in the browser and redraws on every change.

    No request per keystroke.

  • The shell is DSL too

    Sidebar, top bar or a labelled icon rail; navigation groups with descriptions and named sections; the ⌘K command palette and notifications. All authored in PHP. Several panels, each with its own guard, prefix and locales.

    One language for the whole admin.

  • Translatable fields, built in

    Mark a field translatable and it gets per-locale tabs, with rules per locale if you need them.

    Multilingual content is the norm, not a plugin.

  • Media manager, built in

    A library with folders and image variants, and a picker field that plugs into any form.

    One less package to choose and wire.

  • Tables that do the boring things

    Filter tabs, grouping, drag-to-reorder, inline-editable cells, row and bulk actions, and badges and options straight from a PHP enum.

    Most of an admin is tables.

  • Docs written for an agent

    The authoring guide is written for an AI agent and verified against source.

    Your first page in minutes, with an agent or without.

  • Your admin, open to an AI agent

    Turn on the MCP endpoint and an agent uses search, query and execute in-process, with the permissions and validation of the signed-in user. Richtext and repeater fields are described for the agent, dynamic selects answer through query, and execute is flagged destructive so the MCP client can ask first.

    An agent gets the admin, not a second API.

[05]Open by design

Generated screens are the fast path. Your React is the escape hatch.

Register a component once and use it from PHP like any built-in — a field, a block inside a layout, a live widget over form state, or a whole page. No fork, no patching the package.

  • 01 / 04

    A field of your own

    Write one React component for a field type the DSL doesn't ship. Use it from PHP by name, with its own options, next to the 26 built-in field kinds.

    Both sides ship in the same commit.

  • 02 / 04

    Your component in any layout

    Drop a custom component into a table, a section or any other layout, right next to the built-in fields around it.

    The PHP side stays the single source of truth for the page.

  • 03 / 04

    Live UI over unsaved values

    Read the form as the manager types — a running total, a counter, a preview — without a request per keystroke.

    The server still computes the number that gets saved.

  • 04 / 04

    A whole page of your own

    Some screens are not a form or a table. Declare a page, hand it a custom component, and it slots into the admin like any other page.

    Same navigation, same permissions, same admin shell.

[06]Plain answers

Questions teams ask before the first install.

01

Does Tabletop take over my application?

02

Do I need to write React?

03

How does it compare to Filament or Nova?

Read the full comparison
04

Can I use the builder without the CMS?

05

What is the licence?

06

Which versions are supported?

07

What happens if I remove it?

[07]Start

Install it into the app you already have. No new service to run.

Publish the config, run php artisan admin:install and do the four steps it prints, then register a panel and scaffold the first page with make:tbtop-page. Everything else is the Laravel app your team already runs.

Read the docsStar on GitHub
composer require tbtop/admin

Built by DiVotek · Ukraine