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/pages/1/edit
The Tabletop admin: a page editor with block tabs, an SEO tab and a publication panel with schedule fields
app/Admin/Pages/CustomersPage.php
$s->select('city_id')->label('City')    ->dependsOn('country_id')    ->query(fn (array $deps, string $search) =>        City::query()        ->where('country_id', $deps['country_id'])        ->where('name', 'like', "%{$search}%")        ->limit(20)->pluck('name', 'id')->all())    ->creatable(        [$s->text('name')->required()],        fn (array $data) => [            'value' => City::create($data)->id,            'label' => $data['name']],    ),
[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.

tbtop/cms · src/Admin/Pages/PagesPage.php
class PagesPage extends Page{    public function view(S $s): Node    {        $table = $s->table('pages')            ->query($this->query(...))            ->columns([                Column::make('name')                    ->label('Title')                    ->translatable()                    ->emphasized(),                Column::make('display_state')                    ->label('Status')                    ->formatUsing(                        $this->statusLabel(...))                    ->badge([                        'Published' => 'success',                    ]),            ])            ->tabs([                $this->tab('all'),                $this->tab('pages'),            ])            ->searchable(['pages.name'])            ->defaultSort('sort_key', 'asc')            ->rowActions([                $this->duplicateAction($s),            ]);         return $s->stack([$table]);    }}
yourapp.test/admin/pages
The pages list: title, type, status and SEO badges, with filter tabs above
Composition
PHP DSL: pages, tables, forms, actions
Rendering
React client, over Inertia
Backend
Laravel: models, policies, queues, validation
[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: CRM

    Contacts, deals and pipelines on the same builder.

  7. Planned

    Then: Store

    Catalogue, orders and customers.

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

Full roadmap
[04]What you get

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

Nine 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, navigation groups, the ⌘K command palette and notifications are 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.

    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.

[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