- name
- blatui-laravel-blade-components
- description
- CLI that installs shadcn/ui-style Blade components for the BLAT stack (Blade, Laravel, Alpine, Tailwind) into your Laravel project
- triggers
- ["add blade UI components to my Laravel app","install BlatUI components","set up shadcn-style components in Laravel","add accessible Blade components with Alpine","use BlatUI to scaffold UI","install BLAT stack components","add Tailwind Blade components","set up BlatUI in Laravel"]
# BlatUI Laravel Blade Components
> Skill by [ara.so](https://ara.so) — Devtools Skills collection.
BlatUI is a CLI for Laravel that brings shadcn/ui's component philosophy to the **BLAT stack** (Blade · Laravel · Alpine · Tailwind). It copies accessible, themeable UI components directly into your project — you own the code and can customize it freely. Components are built with Blade, styled with Tailwind CSS v4, and use Alpine.js for interactivity.
**Key Features:**
- 156+ accessible components (WCAG AA compliant)
- Components are copied, not installed — you own and edit them
- Full design token system with light/dark mode
- Faithful port of shadcn/ui's design language
- 70 chart types, 64 pre-built blocks
## Requirements
- PHP 8.2+
- Laravel 11, 12, or 13
- Tailwind CSS v4 (required)
- Alpine.js 3
- Node 18+
## Installation
### New Project Setup
```bash
# 1. Install the CLI package
composer require anousss007/blatui
# 2. Install peer dependencies
composer require gehrisandro/tailwind-merge-laravel mallardduck/blade-lucide-icons
npm install -D alpinejs @alpinejs/anchor @alpinejs/collapse @alpinejs/focus
# 3. Publish foundations (theme tokens, Alpine engine, CSS)
php artisan vendor:publish --tag=blatui-foundations
# 4. Verify setup
php artisan blatui:init
```
**Update your Vite entrypoints** (replace contents):
```css
/* resources/css/app.css */
@import "./blatui.css";
```
```js
// resources/js/app.js
import "./blatui.js";
```
The published `blatui.css` includes Tailwind v4, oklch design tokens, and theme presets. The `blatui.js` file bootstraps Alpine with required plugins.
### Existing Project Setup
BlatUI is fully additive. Key considerations:
**Tailwind v4 Migration:**
```bash
# Check your version
php artisan blatui:init
# Migrate from v3 to v4 if needed
npx @tailwindcss/upgrade
```
**CSS Integration:**
```css
/* resources/css/app.css */
@import "tailwindcss";
@import "./blatui.css"; /* Add below Tailwind import */
```
**Alpine.js Integration (if already using Alpine):**
Don't import `blatui.js` — it would create a second Alpine instance. Use `blatui-core.js` instead:
```js
// resources/js/app.js
import Alpine from 'alpinejs'
import { registerBlatUI } from './blatui-core.js'
registerBlatUI(Alpine) // Registers plugins, theme store, chart/calendar engines
window.Alpine = Alpine
Alpine.start()
```
## CLI Commands
### Initialize and Verify
```bash
# Check setup: packages, Tailwind v4, tokens, Alpine wiring
php artisan blatui:init
```
This command validates your entire setup and provides actionable fixes if something is missing.
### List Components
```bash
# List all available components, blocks, and charts
php artisan blatui:list
# Get details about a specific component
php artisan blatui:list select
php artisan blatui:list dialog
php artisan blatui:list button
```
### Add Components
```bash
# Add one component
php artisan blatui:add button
# Add multiple components (dependencies resolved automatically)
php artisan blatui:add button card input select
# Install all components at once
php artisan blatui:add --all
```
Components are copied to `resources/views/components/ui/`. The CLI will notify you of any additional npm/composer packages needed (e.g., charts require `apexcharts`).
## Component Usage
Components are used as Blade anonymous components under the `x-ui.*` namespace.
### Basic Card Example
```blade
<x-ui.card class="max-w-md">
<x-ui.card-header>
<x-ui.card-title>Account Settings</x-ui.card-title>
<x-ui.card-description>
Manage your account preferences
</x-ui.card-description>
</x-ui.card-header>
<x-ui.card-content>
<p>Card content goes here</p>
</x-ui.card-content>
<x-ui.card-footer>
<x-ui.button>Save Changes</x-ui.button>
</x-ui.card-footer>
</x-ui.card>
```
### Button Variants
```blade
{{-- Default --}}
<x-ui.button>Click Me</x-ui.button>
{{-- Variants --}}
<x-ui.button variant="destructive">Delete</x-ui.button>
<x-ui.button variant="outline">Cancel</x-ui.button>
<x-ui.button variant="secondary">Secondary</x-ui.button>
<x-ui.button variant="ghost">Ghost</x-ui.button>
<x-ui.button variant="link">Link Style</x-ui.button>
{{-- Sizes --}}
<x-ui.button size="sm">Small</x-ui.button>
<x-ui.button size="lg">Large</x-ui.button>
<x-ui.button size="icon">
<x-lucide-search class="h-4 w-4" />
</x-ui.button>
{{-- With icons --}}
<x-ui.button>
<x-lucide-mail class="mr-2 h-4 w-4" />
Send Email
</x-ui.button>
```
### Form Components
```blade
<form method="POST" action="/profile" class="space-y-4">
@csrf
{{-- Input --}}
<div class="space-y-2">
<x-ui.label for="email">Email</x-ui.label>
<x-ui.input
id="email"
type="email"
name="email"
placeholder="m@example.com"
value="{{ old('email', $user->email) }}"
required
/>
@error('email')
<p class="text-sm text-destructive">{{ $message }}</p>
@enderror
</div>
{{-- Textarea --}}
<div class="space-y-2">
<x-ui.label for="bio">Bio</x-ui.label>
<x-ui.textarea
id="bio"
name="bio"
rows="4"
placeholder="Tell us about yourself"
>{{ old('bio', $user->bio) }}</x-ui.textarea>
</div>
{{-- Select --}}
<div class="space-y-2">
<x-ui.label for="role">Role</x-ui.label>
<x-ui.select id="role" name="role">
<option value="user">User</option>
<option value="admin">Admin</option>
<option value="moderator">Moderator</option>
</x-ui.select>
</div>
{{-- Checkbox --}}
<div class="flex items-center space-x-2">
<x-ui.checkbox id="terms" name="terms" />
<x-ui.label for="terms" class="font-normal">
I agree to the terms and conditions
</x-ui.label>
</div>
<x-ui.button type="submit">Save Changes</x-ui.button>
</form>
```
### Dialog Component
```blade
{{-- Dialog trigger and content --}}
<div x-data="{ open: false }">
<x-ui.button @click="open = true">
Open Dialog
</x-ui.button>
<x-ui.dialog x-model="open">
<x-ui.dialog-content>
<x-ui.dialog-header>
<x-ui.dialog-title>Confirm Action</x-ui.dialog-title>
<x-ui.dialog-description>
Are you sure you want to proceed?
</x-ui.dialog-description>
</x-ui.dialog-header>
<x-ui.dialog-footer>
<x-ui.button variant="outline" @click="open = false">
Cancel
</x-ui.button>
<x-ui.button @click="open = false">
Confirm
</x-ui.button>
</x-ui.dialog-footer>
</x-ui.dialog-content>
</x-ui.dialog>
</div>
```
### Table Component
```blade
<x-ui.table>
<x-ui.table-header>
<x-ui.table-row>
<x-ui.table-head>Name</x-ui.table-head>
<x-ui.table-head>Email</x-ui.table-head>
<x-ui.table-head>Role</x-ui.table-head>
<x-ui.table-head class="text-right">Actions</x-ui.table-head>
</x-ui.table-row>
</x-ui.table-header>
<x-ui.table-body>
@foreach($users as $user)
<x-ui.table-row>
<x-ui.table-cell class="font-medium">
{{ $user->name }}
</x-ui.table-cell>
<x-ui.table-cell>{{ $user->email }}</x-ui.table-cell>
<x-ui.table-cell>{{ $user->role }}</x-ui.table-cell>
<x-ui.table-cell class="text-right">
<x-ui.button variant="ghost" size="sm">Edit</x-ui.button>
</x-ui.table-cell>
</x-ui.table-row>
@endforeach
</x-ui.table-body>
</x-ui.table>
```
### Alert Component
```blade
{{-- Default alert --}}
<x-ui.alert>
<x-lucide-info class="h-4 w-4" />
<x-ui.alert-title>Information</x-ui.alert-title>
<x-ui.alert-description>
Your session will expire in 5 minutes.
</x-ui.alert-description>
</x-ui.alert>
{{-- Destructive variant --}}
<x-ui.alert variant="destructive">
<x-lucide-alert-circle class="h-4 w-4" />
<x-ui.alert-title>Error</x-ui.alert-title>
<x-ui.alert-description>
Failed to save changes. Please try again.
</x-ui.alert-description>
</x-ui.alert>
```
### Badge Component
```blade
<x-ui.badge>Default</x-ui.badge>
<x-ui.badge variant="secondary">Secondary</x-ui.badge>
<x-ui.badge variant="destructive">Destructive</x-ui.badge>
<x-ui.badge variant="outline">Outline</x-ui.badge>
{{-- With icons --}}
<x-ui.badge>
<x-lucide-check class="mr-1 h-3 w-3" />
Verified
</x-ui.badge>
```
## Theming and Customization
### CSS Variables
All design tokens live in `resources/css/blatui.css` as CSS custom properties (oklch color space):
```css
@theme inline {
--color-background: oklch(100% 0 0);
--color-foreground: oklch(9% 0 0);
--color-primary: oklch(47% 0.2 264);
--color-primary-foreground: oklch(98% 0 0);
/* ... more tokens */
}
.dark {
--color-background: oklch(9% 0 0);
--color-foreground: oklch(98% 0 0);
/* ... dark mode overrides */
}
```
**To customize your theme:**
1. Edit `resources/css/blatui.css`
2. Change the oklch values for any token
3. Changes apply to all components instantly
### Dark Mode
BlatUI uses class-based dark mode. Add the `dark` class to your root element:
```blade
{{-- In your layout --}}
<html class="dark">
{{-- Dark mode active --}}
</html>
{{-- Toggle with Alpine --}}
<div x-data="{ dark: false }" :class="{ 'dark': dark }">
<x-ui.button @click="dark = !dark">
Toggle Dark Mode
在 GitHub 查看