A single file defines how every table, toggle, modal and column in the project behaves: app/Providers/Concerns/ConfiguraFilamentGlobal.php (applied by KitServiceProvider). Change it there, and it changes everywhere — including on third-party plugin screens, which you couldn’t edit any other way.
Also global: modals that do not close on Esc (an accidental tap would discard the form), toggles with state color and icon, boolean icon column with a colored check/x, CreateAction with a default icon and the panel switcher.
Resizable columns on new screens: the default behavior already applies to any table; for the chosen width to be remembered, the list page needs the trait:
use Asmit\ResizedColumn\HasResizableColumn;
classListProdutosextendsListRecords
{
useHasResizableColumn;
}
Four of these defaults are editable in Kit settings, on the Tables tab: rows per page, striped rows, recall of the user’s filter/search/sort, and draggable columns. The same four exist in .env as seed and fallback — KIT_TABELA_PAGINACAO, KIT_TABELA_LISTRADA, KIT_TABELA_PERSISTIR_FILTROS and KIT_TABELA_COLUNAS_REDIMENSIONAVEIS — and the value stored in the database wins. The rest stays a code decision on purpose — those are choices with a written reason, not matters of taste.
⚠️ Table density does not exist in Filament 5, so it is not on the screen. The old TODO here promised four items and one of them has no API: a sweep over vendor/filament/tables/src returns no occurrence of density, and vendor/filament/tables/src/Enums/ holds seven enums, none for density. What the framework does offer as a visual tightness control is striped(), and that is the one that became configurable.
Contrast fixes the kit applies for you
Not everything that decides how a panel looks lives in PHP. Some colour pairs shipped by Filament and by plugins fall short of the 4.5:1 WCAG AA minimum for small text, and the failure is silent: the HTML is correct, the test passes, and it is the user who cannot read it. The kit fixes those cases in resources/css/filament/kit.css, loaded into all three panels through the same mechanism plugins use.
Where
What Filament/the plugin ships
What the kit applies
Active item in top navigation
primary-600 on gray-50 — 3.06:1 on the default palette
primary-700 in light, primary-400 in dark
Environment indicator badge
color-600 on color-50
color-700 in light
Plugin *-primary-* utilities
the literal amber palette from the package build
the panel’s own --primary-* variables
Top navigation
If your panel uses ->topNavigation(), the active item’s label becomes legible in whatever palette you picked. Measured against Filament’s twenty-one named palettes: nine fail at the step the framework applies, and none fails at the step the kit applies. Amber is the default when KIT_COR_PRIMARIA is empty and scores 3.06:1 — a fresh install lands exactly on the worst case.
If your panel uses the sidebar, which is the default, nothing changes. Filament only emits the top items when top navigation is on, so the rule matches no element at all. You can switch between the two modes without thinking about it.
Dark mode is not a detail
Every colour override in the kit ships two rules, one per theme, and that is not fussiness. Filament writes its dark rule as
and :where() contributes zero specificity. An override written for light mode only, with enough specificity to win, wins in both — painting the light colour onto the dark background, making worse exactly what it came to fix.
The dark counterpart is written .dark:root, with the class on the root itself. .dark :root and :root .dark look equivalent and are dead letters: :rootis the <html> element, so it can neither descend from anything nor contain the class the theme switcher writes onto it.
When adding your own colour override, follow the same pairing and run php artisan filament:assets after editing. The guards live in tests/Kit/ContrasteDaNavegacaoNoTopoTest.php and tests/Kit/CorrecaoDeCorPrimariaTest.php: they read the CSS and the vendor/ stylesheets at runtime, recompute contrast against Filament’s own palettes, and turn red when a package upgrade changes the game.
Where to point DocumentRoot — and what the kit does when it is wrong
A Laravel project is served from public/, never from the project root. Your web server’s
DocumentRoot (or your hosting panel’s Document Root) must point at:
/path/to/project/public
On shared hosting that is not always configurable, and the usual workaround is an .htaccess at
the root rewriting everything into public/. It works, with a side effect.
After an internal rewrite, Apache hands PHP SCRIPT_NAME=/public/index.php while REQUEST_URI
still holds what the user asked for. Laravel derives the base URL by comparing the two:
What the browser asked for
Derived base
URLs generated on the page
/app, /admin, /infra
empty
clean
/public/app
/public
all prefixed
So entering once through an address containing /public — an old bookmark, a shared link — is
enough for every link on that page to come out prefixed. Because the .htaccess usually redirects
back, the prefix appears and disappears, which makes the problem look random.
The kit defends itself against this — when it can tell that doing so is safe. It refuses to
honour a base URL ending in /public and rebuilds the root without that suffix, once per request,
but only when there is evidence that / really routes into public/. Without that evidence it
does nothing, and the reason is right below. Three consequences worth knowing:
it covers any panel, including ones you create — the fix is at the URL root, not in a list
of panels;
it covers assets too (/css, /js, /build), which come from the same generator;
on a correct install nothing happens: the base is empty and the check returns on its first
line, with no query and no cost.
This does not excuse fixing DocumentRoot. The kit’s defence strips the prefix from the
URLs the application generates; it cannot stop someone typing /public/... in the address
bar, nor remove the extra redirect the .htaccess performs on every click. If you can
point DocumentRoot at public/, do it.
When the kit strips the prefix, and when it does not. It only shortens the root when there is
evidence that / really routes into public/ — in practice, a RewriteRule pointing at
public/ in the root .htaccess. Without that evidence it does nothing, and the reason is
concrete: an install served at https://host/public/...without a rewrite works exactly like
that, and shortening would turn every link and every asset into a 404.
nginx has no .htaccess to inspect. Declare it by configuration:
KIT_URL_REMOVER_SUFIXO_PUBLIC=true # the rewrite lives in the vhost
KIT_URL_REMOVER_SUFIXO_PUBLIC=false # turn it off entirely
Without the key, the kit detects on its own.
What the defence does NOT reach. It fixes the URLs the application generates. Anything
taken from the request itself keeps the prefix: the intended URL stored when you are bounced to
login (redirect()->guest()) and the “back” link derived from the Referer. A user who reaches
login from /public/app returns to /public/app after authenticating. One more reason to fix
DocumentRoot.