neura-ui/neura-kit
Neura Kit is a Laravel UI component kit from Neura UI, providing ready-to-use Blade components, layouts, and design tokens for building admin panels and dashboards faster. Includes configurable themes, forms, tables, and sensible defaults, with a clean API and minimal setup.
Neura Kit is a Blade + Alpine component library (with Tailwind v4 styling) for Laravel apps. v3.0.0 is MIT, keyless, and a major release: it adds ~12 new components, a shared motion token set, an appearance/theming API, and reworks the installer. Budget a real upgrade pass rather than a patch bump.
1. Install
composer require neura-ui/neura-kit:^3.0
php artisan neura-kit:install
The installer does two things only: it patches the first Vite config it finds (vite.config.js, .mjs, .ts, .mts) and appends the Tailwind @source line to resources/css/app.css. It deliberately leaves app.js untouched.
2. Wire up the JS yourself
Since app.js is not modified, you own Alpine + kit bootstrapping:
import Alpine from 'alpinejs'
import { neuraKit } from 'neura-ui/neura-kit' // resolve actual entry from the package README
import 'neura-ui/neura-kit/style.css' // or the CSS path shipped by the package
neuraKit({ appearance: { style: 'tint', color: 'primary', light: 1, dark: 0.8 } })
window.Alpine = Alpine
Alpine.start()
3. Where to look first
resources/css/motion.css and motion-tokens.ts — the shared duration/easing tokens. Read these before writing any custom animation.config/neura-kit.php), specifically the new json-viewer key.4. First use case
The highest-leverage first swap is an action button with feedback in a Livewire table row, replacing a hand-rolled "Delete" button plus a browser confirm():
<neura::action-button
method="delete"
wire:click="delete({{ $post->id }})"
pending-label="Deleting…"
success-label="Deleted"
reset-after="2000"
variant="danger"
size="sm"
>
Delete
</neura::action-button>
That single component buys you pending state, the ring spinner, a success morph, and reset — all things you would otherwise write three times in Alpine.
The components are Alpine/Blade, not a state layer. The pattern that scales is: Livewire owns the model, the component owns the transient UX (pending, success, confirm, undo).
<neura::confirm-morph
confirm-timeout="4000"
result-timeout="3000"
undo-method="undoArchive"
wire:click="archive({{ $invoice->id }})"
variant="danger"
>
Archive invoice
</neura::confirm-morph>
undo-method is the interesting hook — pair it with soft deletes so the undo window maps to restore(). This gives you a Gmail-style pattern with no custom JS.
neura::button-group (sliding indicator, numeric values scale, other labels crossfade) is the natural binding target for a single Livewire property:
<neura::button-group
wire:model.live="status"
:items="['all' => 'All', 'open' => 'Open', 'closed' => 'Closed']"
variant="soft"
size="sm"
/>
Use attached for toolbars and orientation="vertical" for sidebars. Use neura::expanding-button-group when a collapsed label needs to open a small action set (with confirm-duration) — good for bulk actions on a selection.
neura::split-button exists to stop you building a dropdown next to a submit button. Each menu item accepts its own pending-label, success-label, done-label, reset-after, and color — so a "Save draft / Publish / Schedule" menu can each report its own progress inline.
neura::number-field covers most inventory/quantity UI in one tag: min, max, step, large-step (shift/scrub), prefix, suffix, and the plural pair suffix-one / suffix-many.
<neura::number-field
wire:model.live.debounce.500ms="quantity"
:min="1" :max="$stock" :step="1" :large-step="10"
suffix-one="item" suffix-many="items"
/>
Scrub is opt-in and nice for ops dashboards; avoid it on long forms where accidental drags are expensive.
neura::date-reel — scrolling columns for datetime / date / time, with minute-step and presets. Best for booking and scheduling where you want a fast wheel.neura::calendar / date picker — the selected day now uses the button-group indicator on both axes. Best for ranges and month browsing.neura::time-dial — up to five cities plus a working-hours arc. Genuinely useful for support/ops scheduling across time zones; it is a fixed reading (noon top, 6 left, 18 right, midnight bottom) with only the cursor moving.Normalize every date to Y-m-d strings before binding. The 2.1.10 fix removed a UTC-parse class of bug where the input label and the highlighted day could disagree; don't reintroduce it by passing new Date(...) through a custom formatter.
The native canvas chart gained donut, waffle, and slope.
donut — hover lift, for 3–6 category breakdowns.waffle — 10×10, one cell = 1%, filled column by column from bottom-left. Excellent for "X of 100 seats used" style metrics.slope — exactly two moments, start-label / end-label, rank beside the end, one highlighted series. This is your before/after comparison chart; don't try to force it into a time series.<neura::chart
type="slope"
:rows="$beforeAfter"
start-label="Q1" end-label="Q2" unit="%"
/>
Pair with neura::activity-rings (metrics, days, focused) for a goal/streak header and neura::json-viewer for the payload behind it.
neura::json-viewer (collapsible tree, search that opens matching branches, page-size, copy value or path, keyboard nav) turns "debug panel we never built" into one tag. Use it on webhook delivery logs, Stripe event payloads, and audit diffs. Trim payloads server side and rely on page-size for anything large.
neuraKit({
appearance: { style: 'vivid', color: 'primary', light: 1, dark: 0.75 }
})
light (0–1, stock 1) and dark (0–1, stock 0.7) shift the whole surface ramp together, so borders and text stay in step with the canvas — this is the correct lever for per-tenant branding. Prefer it over overriding CSS variables ad hoc. style is neutral / muted / tint / vivid.
Use the shared values rather than magic numbers: duration-fast 160ms, duration-standard 240ms, duration-considered 480ms, duration-spring 580ms, with ease-standard, ease-enter, ease-spring. They live in resources/css/motion.css and motion-tokens.ts so CSS and TS animations stay in sync.
The installer only patches the first Vite config it finds. If you have vite.config.ts plus vitest.config.ts, or a monorepo with multiple bundlers, verify which file got the change. Same for the @source line — Tailwind v4 will silently purge component classes if the path is missing, and the symptom looks like "component renders unstyled," not like a build error.
app.js is intentionally untouched. That means the kit's JS/Alpine registration is on you. Two ordering rules: start Alpine after calling the kit initializer, and be aware the toast factory registers via onAlpineInit — it now survives Alpine having already started, but if you initialize Alpine after importing the kit's components elsewhere, you can still get a half-registered state. Check the Alpine devtools component tree first whenever a component renders but doesn't respond.
Reduced motion is only half-automatic. The global CSS rule collapses animation-duration and transition-duration, but element.animate() is not affected. Any scripted motion you add must call prefersReducedMotion() itself. The kit does this internally (travel is dropped, end state kept) — copy that pattern.
Expect visual drift when upgrading to 3.0. Popups, tooltip, toast, table, kanban, dropzone, flow, and the filters panel were all moved onto the shared surface tokens and the menu-morph open animation. If you had local overrides on any of those, delete them first and re-add only what's still needed — stacking your old shadows/borders on the new ramp is the most likely source of "it looks off after upgrade."
Remove license-key plumbing. v3 is MIT with no key. Any NEURA_LICENSE env var or activation call in your bootstrapping is now dead weight.
Toast stacking changed. Bottom-stacked, three visible with a peek and scale step, drag to dismiss, optional progress. If you pinned toast position with custom CSS, drop it and use the component's own config.
Table search field is borderless and fill-less, including on focus. Don't fight it with ring utilities — wrap it in a container if you need a visible affordance.
Filters value segment keeps a fixed width (w-28 through w-44 by size pack). This is intentional so switching parameter doesn't resize the chip, which means long parameter labels truncate. Keep them to one short word.
Waffle color fallback. If you pass a backgroundColor array that resolves to a single distinct color, the chart falls back to the palette instead of painting everything flat. Pass multiple colors or omit the array entirely.
Slope charts have assumptions. Exactly two moments; the legend is off; the y scale follows the data rather than being forced through zero. That last point means slopes are not comparable across two charts with different domains — label the axis or show values.
JSON viewer search caps at 2000 matches and strings over 40 characters ellipsize. For very large documents, page server-side rather than leaning on page-size alone.
Time dial is fixed-orientation. Noon top, 6 left, 18 right, midnight bottom, city marks on the face. Don't try to rotate it; treat it as a read-only visual with a draggable cursor.
Signature pad gives you a PNG, not a form value. Wire the download/capture into a Livewire upload or a hidden base64 field, and validate size and mime type server side like any other user-supplied file.
Drop any workaround for rule-builder drag. v3 fixed reordering (within the parent list, order written back). Custom drag shims will now conflict.
Debugging checklist, in order: Alpine started after the kit initializer? → @source present in app.css? → php artisan view:clear && npm run build? → local CSS overrides removed? That sequence resolves most "component doesn't work / looks wrong" reports with this package.
Extension points worth knowing: the motion token files (for consistent custom animation), the json-viewer config key and global rounded style, the appearance ramp (for theming), and the EN/FR string set — if you ship other locales, plan to supply your own strings for the newer form and action controls.
How can I help you explore Laravel packages today?