Skip to content
LarawellUi

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:diff shows what you'd miss. larawellui.lock keeps track, like composer.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.
Terminal
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.

Content-Security-Policy, as sent with this page
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 survive wire: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.