LarawellUI:34 个无需 JavaScript 框架的 Laravel Blade + Tailwind v4 组件
I Built Laravel UI Widgets That Don't Need a JavaScript Framework Called LarawellUI.
开发者发布 LarawellUI,提供 34 个基于 Blade + Tailwind v4 的服务端渲染组件,每个组件仅依赖一个小型原生 JS 文件,通过 composer require --dev larawellui/larawellui 安装,采用 shadcn/ui 式"复制即拥有"模式。
I've copied the same hand-rolled datepicker between Laravel projects more times than I want to admit. Every time, I'd look at the existing UI kits first, and every time I'd close the tab.
The problem wasn't quality. It was the price of entry. Most Laravel UI kits ask you to adopt their JavaScript along with them — bring Alpine, bring Livewire, or rebuild your frontend in React or Vue. If you're running a plain server-rendered Blade app, that's a significant architectural commitment in exchange for a date field.
So I built LarawellUI: 34 Blade + Tailwind v4 widgets, server-rendered, with a small vanilla JS file behind each one.
Copy in, don't depend on
The install is a dev dependency, and the widgets themselves land in your app:
composer require --dev larawellui/larawellui
php artisan larawell:add datepicker
npm run build
larawell:add copies the widget's source into your application along with anything it depends on. From that moment it's your code. Rename the classes, rip out half the markup, change the keyboard behavior — nobody's stopping you.
This is the shadcn/ui model, and I think it's correct for UI components specifically. A UI widget is not a hashing library. You will need to change it. The question is whether you're fighting a package's config surface or just editing a file.
The part that usually breaks
Copy-and-own has one well-known failure mode: you own it, so you never get updates again. Six months later you're on a fork of a fork and the upstream bugfixes may as well not exist.
LarawellUI keeps a lock file recording the state of every file it wrote. When you update:
Files you haven't touched get replaced with the new version.
Files you've edited are skipped and listed in the output, so you know what you're now maintaining yourself.
larawell:diffshows exactly what upstream changed, so you can port the fix by hand if you want it.
Nothing is overwritten silently. That was the non-negotiable.
Three constraints I didn't want to compromise on
It has to run under a strict CSP. No inline <script>, no onclick attributes, no style="". If you've ever tried to retrofit a Content Security Policy onto an app full of inline handlers, you know it's a nightmare that never fully ends. Every widget wires itself up from an external JS file via data attributes.
It has to survive Livewire. No Alpine or Livewire is required, but plenty of people use both — and DOM morphing destroys naive components. Everything is tested inside Livewire 3 and 4 against wire:model, morphs, and wire:navigate, in a real browser rather than a jsdom approximation.
Accessibility and i18n aren't a later milestone. Keyboard navigation, correct ARIA roles and states, RTL layouts, and dates and numbers formatted in your app's locale. A datepicker that only works with a mouse and only speaks en_US isn't a datepicker, it's a demo.
What's in the set
Datepicker, date-range picker, time picker, select, phone input, OTP input, file upload, table, modal, toast, tabs, stepper, tooltips, and about twenty more.
There's also an angle I didn't expect to care about but now use constantly: a built-in MCP server (php artisan larawell:mcp), plus /llms.txt and JSON registry endpoints. Your coding agent can list the available widgets, read the props, and run the install command itself. Telling Claude or Cursor "add a date range picker to this form" and having it pick the right widget turns out to be a reasonable workflow.
Try it
Live previews, props and source for every widget: https://larawellui.wasmer.app/
PHP 8.3+, Laravel 12 and 13, MIT licensed.
来源:Google AI:DEV 作者专属(RSS) · dev.to