beartropy/ui
Beartropy UI is a TALL stack component library for Laravel and Livewire with 40+ Tailwind-powered components, including modals, dropdowns, date pickers, a command palette, and dark mode support.
composer require beartropy/ui. Requires Tailwind, Alpine, Laravel, and Livewire 3.6+ (Livewire 4 is supported as of v1.0.19).@beartropyAssets resolves stable cache-busting versions (see Gotchas — running unpublished assets works but has caveats). Typical call: php artisan vendor:publish --tag=beartropy-ui-assets (and --tag=beartropy-ui-lang if you want the Spanish translations).@beartropyAssets inside <head> in your layout. As of v1.0.6 this directive also injects the FOUC-prevention theme script, so you do not need <x-bt-theme-head /> separately unless you want explicit control.<x-bt-button> next to a <x-bt-input wire:model="name"> inside a Livewire component, wrap in a <x-bt-modal>, and toggle the theme with <x-bt-toggle-theme />. If dark mode flips cleanly and the modal opens without FOUC, your setup is sound.If you are using AI coding tools, run the skills installer (or copy docs/ai-assistants/cursor/.cursorrules for Cursor). The Claude Code slash commands (/bt-ui-form, /bt-ui-livewire, /bt-ui-component, /bt-ui-patterns, /bt-ui-setup) are the fastest way to get idiomatic usage — they surface component props you would otherwise have to hunt for on the docs site.
Blade-first, Livewire-aware. Components use the x-bt-* prefix (x-bt-button, x-bt-input, x-bt-select, x-bt-modal, x-bt-dropdown, x-bt-datetime, x-bt-table, x-bt-chat-input, etc.). They bind to Livewire the same way native inputs do, so wire:model="prop" and wire:model.live work as expected. There is a dedicated /bt-ui-livewire skill that documents the Livewire-specific props and event wiring.
Forms. Compose forms by nesting x-bt-input, x-bt-select, x-bt-datetime, x-bt-file-input, x-bt-slider inside x-bt-form. The Lookup and Select components share the same teleported dropdown base, so widths and positioning behave consistently once you tune minWidth / maxWidth (see below).
Layouts and navigation. Use the shipped layout components for the shell, then x-bt-nav for the sidebar. Active state uses segment-aware path matching (fixed in v1.0.14), so /request no longer highlights when you are on /requested. If you build nested nav, rely on this behavior instead of hand-rolling request()->is() matching.
Tables. x-bt-table gives you a header with a built-in search input and an actions slot on the top-right (v1.0.15+) for bulk buttons, filters, or export controls. Combine with wire:model.live on the search field to drive Eloquent scopes in your Livewire component.
Theming. Prefer @beartropyAssets + <x-bt-toggle-theme />. If you need zero-FOUC on first paint, add @beartropyHtmlClass (v1.0.10+) which reads the bt_theme cookie server-side and renders class="dark" on <html> before CSS loads. Persistence is dual: cookie plus localStorage, so SSR and client agree. Theme presets (slate, gray, zinc, neutral, stone, and the color presets) are configurable, and many components have per-preset styling.
Toasts. Register notifications through the toast API. A global timer registry handles hover-pause correctly (v0.9.43) — do not try to x-init your own timers on top of the component.
External triggers. Components that expose programmatic control use $dispatch events — e.g. open-slider, close-slider, toggle-slider on x-bt-slider (v0.11.18+). These use native addEventListener in init(), so they work across Livewire component boundaries, unlike Alpine $dispatch-only patterns.
AI-assisted workflow. For anything beyond trivial usage, the MCP integration (Laravel Boost tools beartropy-component-docs and beartropy-list-components, plus beartropy-project-context for your local config) is the intended path to accurate prop signatures. If you are not on Boost, the static guide at vendor/beartropy/ui/docs/ai-assistants/BEARTROPY_GUIDE.md is a reasonable fallback and is safe to paste into prompts.
i18n. Publish beartropy-ui-lang to override or extend strings; the package ships en and es and picks up Laravel's app()->getLocale() automatically.
wire:navigate, you are either missing @beartropyAssets in <head> or you removed the inline theme script. Do not reorder it after your main CSS.@beartropyAssets uses filemtime() (v1.0.14+) so the ?v= string is stable. If you are on an older version you will see duplicated <script>/<link> tags after wire:navigate due to the changing time() fallback. Publishing to public/ sidesteps this entirely — do it for production.12rem–32rem, TimePicker 12rem–22rem, Datetime 16rem–25rem. If a dropdown is stretching to viewport width, the trigger was narrower than minWidth or you removed fitAnchor from Datetime — set minWidth / maxWidth explicitly.@click.outside. v1.0.7 removed an unnecessary @click.stop on the modal container and simultaneously made Select close correctly inside modals. If you are on an older patch and Selects do not close inside a modal, upgrade — do not work around by removing stopPropagation in your app.start area so end is yours. If you upgraded and your status icons vanished, you are still rendering them into end — move them.FileInput’s upload listener forgiving of a missing detail.property. If you are writing a custom upload handler that dispatches that event, include property so downstream versions keep working.content globs (make sure vendor/beartropy/ui/resources/views is included) or the safelist is stale — upgrade to at least v1.0.7 where the dialog color safelist was fixed.wire:navigate specifics. Head elements use data-navigate-once” so Livewire does not rip them out on navigation. If you author your own layout wrapping @beartropyAssets in a Livewire-rendered partial, you can break this guard. Keep it in the static Blade layout.$dispatch and let the component’s native listener pick it up; Alpine-only x-on handlers in sibling components will not fire reliably across Livewire boundaries (that is why v0.11.19 moved to addEventListener).@click on <x-bt-icon> is not firing, you are below that version.How can I help you explore Laravel packages today?