jksantos/jetax
Jetax é um design system opinativo para a TALL Stack em PHP 8.4+ e Laravel 12+: rode o instalador e tenha sidebar, topbar, workspace e 60+ componentes Blade/Livewire prontos, com dark mode nativo, tipografia Manrope/Inter e tudo publicável para customização.
Jetax is an opinionated TALL-stack design system: one Composer install and you get a full app shell (<x-jetax-layout> with sidebar, topbar, workspace), a themed token layer, and 60+ <x-jetax-*> Blade/Livewire components. It is not a component "kit" you cherry-pick from — it wants to own your visual layer.
Before writing a single line, confirm the floors are non-negotiable: PHP 8.4+, Laravel 12+, Livewire 4+, Tailwind 4+. There is no backport path. If your project is on Livewire 3 or Tailwind 3, stop here — this package is not for that codebase.
Minimal path:
composer require jksantos/jetax
php artisan jetax:install
The installer publishes the CSS source and wires the @import into your main stylesheet. Then verify two things by hand, because the installer is the most likely place to fail silently:
resources/css/app.css contains, in this exact order — Google Fonts and Material Symbols first, then @import "tailwindcss", then the Jetax import, then the @source directive:@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@300;600;700;800&family=Inter:wght@400;500;600&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,[email protected],100..700,0..1,-50..200&display=swap');
@import "tailwindcss";
@import "../../vendor/jksantos/jetax/resources/css/jetax.css";
@source "../../vendor/jksantos/jetax/resources/views";
@livewireStyles in <head> and @livewireScripts before </body>. Alpine ships with Livewire — do not add a second Alpine script tag.Where to look first, in order: config/jetax.php (published via --tag=jetax-config) for tokens and the DataTable defaults; resources/views/components/ inside the vendor package to see what each component actually accepts; and the changelog, which is unusually candid about real bugs and reads like a field-notes file.
First use case — a CRUD index screen. This is the fastest way to learn the conventions:
<x-jetax-layout>
<x-slot:title>Clientes</x-slot:title>
<x-jetax-page-header title="Clientes" subtitle="Gerenciar base de clientes">
<x-jetax-button variant="primary">Novo cliente</x-jetax-button>
</x-jetax-page-header>
<x-jetax-card>
<x-jetax-table :headers="['Nome', 'Email', 'Status']" :rows="$clientes" />
</x-jetax-card>
</x-jetax-layout>
Run php artisan jetax:check immediately after install and add it to CI. It reports published views that have drifted from the vendor originals — the single most useful maintenance command in the package.
Use the layouts, don't rebuild them. <x-jetax-layout> is the authenticated shell; <x-jetax-auth-layout> is the login/register shell. Both carry the anti-FOUC dark-mode script. If you hand-roll a layout, you lose the theme bootstrap and get a white flash on every page load for dark-mode users. Build your pages as slot content inside these, not as sibling layouts.
Form components pair with wire:model directly. Inputs, selects, toggles, date/time, currency, pin, tag and upload are Livewire-native — they take props, attributes and slots, so standard wire:model.live, wire:loading.attr="disabled" and wire:dirty flow through unchanged. The practical pattern is one Blade partial per form section, each field a <x-jetax-input> with the error key derived from the model name, plus <x-jetax-validation> at the form level. Do not wrap these in your own abstraction early; the components already handle label/error/help-text layout and you will fight the wrapper later.
Table + pagination is the highest-touch integration point. The DataTable expects a paginator and, per the 1.1.x changelogs, manages page and per_page as URL parameters itself. The working pattern:
per_page in the allowed set [10, 25, 50, 100] — the config default was deliberately changed from 15 to 10 because 15 is not in the selector and left the dropdown visually blank.withPath() and appends(['per_page' => ...]) on the paginator; if you build your own paginator wrapper, replicate both or you get /admin/admin/tenants 404s and a "rows per page" selector that silently no-ops.Overlay feedback is event-driven. toast and dialog respond to dispatched Livewire events. The idiomatic flow is: Livewire action → $this->dispatch('toast', ...) on success → component renders. Don't try to control toasts by toggling a public property on every page; that leads to per-page boilerplate.
Customise from the outside in, not by editing published views. In order of preference:
card gained headerClass/footerClass in 1.1.0 precisely so you can restyle the header without forking. Check the component's props before publishing anything.--color-primary, --color-surface, etc. in your own @theme block or via config/jetax.php. Since 1.1.0 the dark theme overrides --color-* directly, so Tailwind utilities (bg-primary, text-on-surface) respond to theme switches automatically — this is the cleanest lever you have.--tag=jetax-css-source) when you need structural changes to the stylesheet.--tag=jetax-views) as a last resort, and then scoped — publish one component, not all sixty.Dark mode is already solved; don't re-solve it. Class strategy, localStorage persistence, anti-FOUC inline script, and (since 1.1.0) a @custom-variant dark shipped inside the package so it works without your app declaring one. Your job is only to avoid hardcoding light-only colours — use bg-surface, text-on-surface, border-outline rather than bg-white/text-slate-900.
Component naming gives you a clean exit ramp. Everything is namespaced <x-jetax-*>. If you later swap the design system out, a project-wide grep for <x-jetax- is your complete work list. Preserve that property — never alias Jetax components into un-prefixed names of your own.
CSS import order is a hard constraint. Google Fonts and Material Symbols must be the first @imports in the file — before @import "tailwindcss" and before the Jetax import. The package deliberately does not bundle them because Vite/Tailwind emit build warnings for external URLs inside package CSS. Get this wrong and you get either build noise or silent font fallback to system fonts. If your typography looks generic, this is the first place to look.
The @source directive is load-bearing. Tailwind 4 does not scan vendor/ by default. Without @source "../../vendor/jksantos/jetax/resources/views"; every class used only inside Jetax views gets purged and components render structurally correct but visually broken — no spacing, no colours, no borders. If a component looks "half-applied", this is almost always the cause.
Pin the version and read the 1.1.x changelog before upgrading. The DataTable fixes in 1.1.1 and 1.1.2 are real behavioural corrections (perPage → per_page, withPath(), appends(), default 10). If you built pagination workarounds against 1.0.x, upgrading will double-apply them. Pin exact versions in composer.json and treat minor bumps as reviewable changes.
Published views drift silently. Once a view is in resources/views/vendor/jetax/, upstream fixes never reach it. php artisan jetax:check exists to catch exactly this — run it in CI, not manually. The related trap: publishing all views "just in case" guarantees a permanent fork and forfeits every future bugfix.
Dark-mode CSS conflicts. Since 1.1.0 the package declares its own @custom-variant dark (&:where(.dark, .dark *)). If your app also declares one, you now have two competing definitions and the cascade order decides. Audit your app.css before installing on an existing project rather than after.
Alpine comes from Livewire. Adding your own Alpine <script> tag on top of @livewireScripts produces duplicate-instance bugs that look like unrelated component failures — accordions that open twice, dropdowns that never close. Remove any pre-existing Alpine include.
Debugging checklist when a component misbehaves: (a) is the view coming from vendor/ or from a published override — check php artisan view:clear then look at the actual path; (b) is @source present and is the relative path correct for your project depth; (c) did the class survive Tailwind's scan — inspect the compiled CSS, not just the DOM; (d) for DataTable specifically, check the URL for both page and per_page, since several historical bugs were URL-parameter mismatches.
Documentation is Portuguese-only and the project is unproven. Zero stars, zero dependents, first release cycle. Treat this as an internal-tool-grade dependency: vendor-review the component source before committing to it, and budget for reading the Blade files as your primary documentation. The x-jetax- prefix is what makes this a reversible bet.
Extension points worth knowing up front: jetax_config() helper for config reads inside your own components (keeps defaults in one place), headerClasses()/footerClasses() on card as the pattern for class-override methods, and the @theme token block as the sanctioned restyling surface. Reach for view publishing only after those three are exhausted.
How can I help you explore Laravel packages today?