A beautifully crafted set of Blade UI components for Laravel. Browse them, then add the ones you need straight into your app — once added, the code is yours to keep and customize. No black boxes, no lock‑in.
Built with Tailwind CSS v4 and Alpine.js. Works great with Livewire.
The semantic variables in the published stylesheet are also a versioned
portable styling contract: devdojo.theme@1. Designer blocks that declare
this contract carry their HTML/CSS/JS but inherit colors, fonts, radii, and
dark-mode values from the app they are inserted into. The canonical contract
metadata is available from DevDojo\Components\Theme\ThemeContract.
<x-button>Get started</x-button>
<x-input label="Email" type="email" wire:model="email" />
<x-alert variant="success" title="Saved!" description="Your changes are live." />Most component libraries hide their markup behind a dependency. DevDojo Components
takes the opposite approach (à la shadcn/ui): you preview everything from the
package, then add the components you want into
resources/views/components/. They become ordinary
anonymous Blade components
that you own and can edit freely.
- PHP 8.2+
- Laravel 11, 12, or 13
- Tailwind CSS v4
- Alpine.js (bundled with Livewire, or include it yourself)
composer require devdojo/componentsThen publish the theme. There are two ways — pick one:
php artisan components:installThis copies resources/css/components.css (the design tokens) and adds
@import './components.css'; to your resources/css/app.css, right after the
tailwindcss import. Re‑run with --force to overwrite a previously published
theme. Finally, rebuild your assets:
npm run build # or: npm run devPrefer this when your CSS entry point isn't the standard
resources/css/app.css, or you want to place the import yourself:
php artisan vendor:publish --tag=components-themeThen import the tokens from your main stylesheet, above your own styles:
@import 'tailwindcss';
@import './components.css';If you use the preview namespace (<x-components.button />) in your views
before adding components, also point Tailwind at the package sources so their
classes compile (components you add live in resources/views and are picked
up automatically):
@source '../../vendor/devdojo/components/resources/components';Both paths publish the same theme file — the installer is simply the two‑minute version of the manual steps.
The theme enables class‑based dark mode — add the
darkclass to your<html>element to switch.
Before adding a component, every one is available under the components
namespace so you can try it instantly:
<x-components.button variant="primary">Preview me</x-components.button>In your local environment you also get a full gallery at /components
that renders every component in light and dark mode.
config/components.php (publish with php artisan vendor:publish --tag=components-config).
The full reference:
return [
// Register the preview namespace so every component can be used as
// <x-components.button /> straight from the package, before you add it.
// Disable to stop the bundled components from being registered at all.
'preview' => true,
// Where `php artisan components:add` writes components, relative to your
// resource path. Each component becomes its own folder, e.g.
// resources/views/components/button/index.blade.php → <x-button />.
'path' => 'views/components',
// The built-in gallery/Studio. Only ever registered in the "local"
// environment. `middleware` must include the session + CSRF stack (the
// "web" group) so the Livewire "add" buttons can post back; `assets` are
// the Vite entry points loaded by the studio pages and preview iframe.
'showcase' => [
'enabled' => env('COMPONENTS_SHOWCASE', true),
'route' => '/components',
'middleware' => ['web'],
'assets' => ['resources/css/app.css'],
],
// The standalone, production-safe preview endpoint (details below).
'preview_route' => [
'enabled' => env('COMPONENTS_PREVIEW_ROUTE', false),
'middleware' => ['web', 'throttle:120,1'],
],
];The standalone preview endpoint (GET {showcase.route}/{name}/preview, named
devdojo-components.preview) renders one component as an isolated document —
input is neutralized and the response is cacheable, so it's safe to run in
production even with the Studio (showcase.enabled) turned off. It's off
by default out of the box — the consuming app opts in by setting
COMPONENTS_PREVIEW_ROUTE=true (or publishing the config and flipping
enabled) when it wants its own component gallery or docs page to embed a
live preview. Tighten middleware (e.g. a stricter throttle) per app as
needed.
List what's available:
php artisan components:listAdd components interactively (multi‑select), or pass names directly:
php artisan components:add # interactive picker
php artisan components:add button alert # add specific components
php artisan components:add --all # add everythingEach component is written to its own folder as an index component, e.g.
resources/views/components/button/index.blade.php, so you use it as
<x-button>. Dependencies are resolved automatically — adding input also
adds label; adding modal also adds button.
Re‑run with --force to overwrite components you've already added.
| Component | Use it as | Notes |
|---|---|---|
| Button | <x-button> |
6 variants, 7 sizes, link mode, Livewire loaders |
| Input | <x-input> |
Optional label + automatic validation errors |
| Label | <x-label> |
Accessible form label |
| Checkbox | <x-checkbox> |
Label, description, custom icon, clickable rows |
| Radio | <x-radio> |
Same API as checkbox |
| Toggle | <x-toggle> |
Animated switch, 3 sizes |
| Card | <x-card> |
Header / footer slots, 3 sizes |
| Modal | <x-modal> |
Teleported, focus‑trapped dialog |
| Dropdown | <x-dropdown> |
Click‑to‑open menu anchored to a trigger |
| Popover | <x-popover> |
The dropdown's positioning engine, fully placeable |
| Tooltip | <x-tooltip> |
Pure‑Alpine, hover/focus, 4 positions |
| Drawer | <x-drawer> |
Teleported slide‑in panel (left/right) |
| Alert | <x-alert> |
6 contextual variants with built‑in icons |
| Toast | <x-toast> |
Global notification stack |
| Monaco Editor | <x-monaco-editor> |
The VS Code editor — needs JS assets ⚡ |
| Tiptap | <x-tiptap> |
Rich‑text WYSIWYG editor — needs JS assets ⚡ |
monaco-editor and tiptap lazy‑load a compiled JavaScript bundle. After
adding either, publish the bundles once:
php artisan vendor:publish --tag=devdojo-assetsThis copies the editors' JS/CSS into public/devdojo/. They are loaded on
demand the first time the component appears on a page — nothing is added to your
main bundle. To rebuild the assets from source (in this package):
npm install && npm run build # outputs to public/devdojoDrop a single <x-toast /> into your layout, then trigger notifications from:
// JavaScript / Alpine
window.toast('Saved successfully!', 'success', 'Optional description.');// Livewire
$this->dispatch('pop-toast', message: 'Saved!', type: 'success');
// Or flash from a controller
return back()->with('toast', ['message' => 'Saved!', 'type' => 'success']);All colors and radii are CSS variables in resources/css/components.css. Change
them once and every component updates — in both light and dark mode:
:root {
--primary: oklch(0.55 0.21 264); /* make the brand blue */
}Components use tailwind-merge-laravel
so any classes you pass intelligently override the defaults:
<x-button class="rounded-full px-10">Pill</x-button>composer testBuilt by Tony Lea and the DevDojo community. Many components began life in KatanaUI.
The MIT License (MIT). See LICENSE.md.