Why LarawellUi
Yours to edit. Already tested.
A component library usually makes you choose: install a package you can't change, or paste snippets nobody tested together. LarawellUi copies finished components into your app, as your code, after they've been through what a component rarely gets: a strict Content Security Policy, real Livewire renders and an accessibility check on every change.
- components, each with live examples
- 36
- packages your app needs at runtime
- 0
- times your CSP needs 'unsafe-inline' for them
- 0
- Livewire versions each one is checked in
- 3 & 4
You own every line
And you still get updates.
- One Artisan command copies a component's Blade, JavaScript and CSS into your app, with what it depends on. From then on it's your file: change a default, a colour or a label right where it's set.
- Updates still reach you. Files you haven't edited get the new version; files you have are skipped and reported, and
larawell:diffshows what you'd miss.larawellui.lockkeeps track, likecomposer.lock. - The package only does the copying, so it stays a dev dependency. Nothing of ours runs in production, and nothing breaks if you remove it.
php artisan larawell:add datepicker # copies it in, with field and icon
# edit resources/views/components/widget/datepicker/… as you like
php artisan larawell:add --installed # later: updates what you haven't edited
php artisan larawell:diff # and shows what it skipped
Safe under a strict CSP
Don't take our word for it: this page is the proof.
No component renders an inline script, an onclick or a style attribute, so your Content Security Policy never needs 'unsafe-inline' for them. Every page of this site is served with the policy below, this one included, and every live example runs under it. Open your browser's developer tools and compare it with this page's response headers.
default-src 'self';
script-src 'self' 'nonce-eJxAnhACHML4S4zX4gM33WPq9OSF0pC4' https://challenges.cloudflare.com;
style-src 'self' 'nonce-eJxAnhACHML4S4zX4gM33WPq9OSF0pC4';
img-src 'self' blob:;
frame-src https://challenges.cloudflare.com;
object-src 'none';
base-uri 'self';
form-action 'self';
frame-ancestors 'none'
The nonce changes with every request and covers the site's own few inline tags. The Cloudflare address is there for the captcha's Turnstile example. Your app needs neither for the components.
Livewire-ready, Livewire-free
Plain Blade and one small vanilla JS file per component. No Alpine, no Livewire needed.
Put them inside a Livewire 3 or 4 component and they hold up through every render, checked in a real browser, not assumed:
- Inputs bind with
wire:model, keep focus while someone types and show validation errors under the property. - An open modal or menu stays open, a panel stays as it was left, a running stopwatch keeps running.
- The file upload sends files to Livewire's temporary uploads and keeps its previews through renders.
- Toasts come from
$this->dispatch()and survivewire:navigate, and components a render brings in set themselves up.
Every component's page shows it inside a Livewire component, under Usage.
Accessible by default
Checked on every change, not once at launch.
- Keyboard support, ARIA and focus handling are built in, and so are right-to-left layouts and dates and numbers in your app's locale.
- Every example is checked with axe-core against WCAG 2.2 A and AA, in light and dark, as the page draws and with each popover, dialog, toast and tooltip opened. A change that fails can't be merged.
- Where axe can't decide, such as contrast on SVG text, the test measures the colours itself instead of letting it pass.
Each component's page says what it was checked against, under Accessibility. A screen reader and a keyboard still need a person: check those on your pages too.
Your agent can install it
The same catalogue, in a form an AI agent reads.
Props, working examples and full source for every component, plus an MCP server in your app that knows what's installed, what you've edited, and installs with a dry run first.
- /llms.txt
- An index of every component, for agents that follow the llms.txt convention.
- /r/index.json
- Every component, with a link to its full entry.
- /r/datepicker.json
- One component's full entry: install command, props, examples and source.
- php artisan larawell:list --json
- The same catalogue offline, from the installed package.
- php artisan larawell:mcp
- An MCP server in your app: the catalogue, what this app has installed and edited, and installing with a dry run first.
Three ways to get components
Each has its place. Here's where copying tested components in comes out.
| What you get | Copied in, like LarawellUi | A package you install | Snippets you paste |
|---|---|---|---|
| Change any line of the source | Yes, it's your file | By overriding its views | Yes |
| Updates | One command; your edited files are kept | composer update, nothing to review | By hand |
| Runs in production | Your copies only | The package | Your copies only |
| Tested together: CSP, Livewire, accessibility | On every change | Depends on the package | Rarely |
When it's not for you
Better to know now than after an afternoon.
- Your project is on Tailwind CSS v3, Bootstrap or another CSS framework. The components use Tailwind v4.
- Your pages are React or Vue through Inertia. The components are Blade.
- You'd rather never see a component's code. An installed package, updated with
composer update, suits that better. - You need browsers from before 2024. The select, date pickers, dropdown and tooltips are built on the browser's own popover; the browser list has the details.
Try one in five minutes
Laravel 12 or 13 with Vite and Tailwind CSS v4, which new Laravel apps have out of the box. Free and MIT licensed.
composer require --dev larawellui/larawellui
Then php artisan larawell:add datepicker, or run it with no name to pick from the list.