Tailwind CSS Prefixing for Modules
How LaraDashboard modules use Tailwind CSS v4 prefixing to isolate styles and prevent class conflicts between modules.
Tailwind CSS Prefixing for Modules
Every LaraDashboard module that ships its own CSS uses Tailwind CSS v4 prefixing to namespace utility classes. This prevents style conflicts between modules that run on the same page.
Why Prefixing?
When multiple modules are active, each generates its own CSS bundle. Without prefixing, a .bg-white from Module A could conflict with .bg-white from Module B or the core app. Prefixing ensures each module's utilities are scoped.
How It Works
1. Declare the Prefix
In your module's resources/assets/css/app.css:
@import "tailwindcss" prefix(crm);
This generates all Tailwind utilities with the crm: prefix: crm:bg-white, crm:flex, crm:py-4, etc.
2. Use Prefixed Classes in Blade
{{-- Module-specific classes use the prefix --}}
<div class="crm:py-6 crm:px-4 crm:bg-white crm:dark:bg-gray-900 crm:rounded-lg">
<h2 class="crm:text-xl crm:font-semibold crm:text-gray-900 crm:dark:text-white">
Contacts
</h2>
<p class="crm:mt-2 crm:text-sm crm:text-gray-600 crm:dark:text-gray-400">
Manage your contacts here.
</p>
</div>
3. Shared Classes Do NOT Use Prefix
Classes from the core app's resources/css/components.css are globally available without any prefix:
{{-- Core component classes — no prefix needed --}}
<button class="btn btn-primary">Save Contact</button>
<input type="text" class="form-control" placeholder="Search...">
<label class="form-label">Name</label>
<span class="badge badge-success">Active</span>
<div class="card">
<div class="card-header">
<h3 class="card-title">Card Title</h3>
</div>
<div class="card-body">Content</div>
</div>
4. Mix Shared + Prefixed
In practice, views combine both:
<div class="card">
<div class="card-header crm:flex crm:items-center crm:justify-between">
<h3 class="card-title">Contacts</h3>
<a href="{{ route('admin.crm.contacts.create') }}" class="btn btn-primary btn-sm">
Add Contact
</a>
</div>
<div class="card-body crm:p-0">
{{-- Datatable component --}}
</div>
</div>
Existing Module Prefixes
| Module | Prefix | Example Usage |
|---|---|---|
| CRM | crm |
crm:py-4 crm:flex crm:gap-2 |
| Starter26 (theme) | st |
st:py-4 st:flex st:gap-2 |
| DocForge | df |
df:py-4 df:flex |
| Ecom | ecom |
ecom:py-4 ecom:flex |
| Forum | forum |
forum:py-4 forum:flex |
| Review | review |
review:py-4 review:flex |
| Custom Forms | cf |
cf:py-4 cf:flex |
| LaraDashboard Core | ld |
ld:py-4 ld:flex |
| LaradashboardPro | laradashboardpro |
laradashboardpro:py-4 |
Tip: Choose a short prefix (2-5 characters) for readability. Shorter is better.
Full CSS Setup
resources/assets/css/app.css
@import "tailwindcss" prefix(crm);
/* Class-based dark mode (matches core app) */
@custom-variant dark (&:is(.dark *));
/* Tell Tailwind where to scan for class usage */
@source '../../views/**/*.blade.php';
@source '../js/**/*.js';
/* Define theme colors */
@theme {
--color-primary: #635bff;
}
/* Safelist classes used dynamically (Alpine.js, Livewire, etc.) */
@source inline("border-primary border-2 border-gray-200 border-gray-300");
@source inline("bg-primary bg-primary/5 bg-primary/20 bg-white");
@source inline("text-primary text-primary/80");
/* Inherit theme color from core app at runtime */
@layer base {
:root, :host {
--crm-color-primary: var(--color-primary, #635bff);
}
}
/* Module-specific component styles (optional) */
@layer components {
/* Custom styles here */
}
Key Sections Explained
| Section | Purpose |
|---|---|
prefix(crm) |
Namespaces all Tailwind utilities |
@custom-variant dark |
Matches core app's class-based dark mode |
@source |
Tells Tailwind where to scan for used classes |
@theme |
Defines module's color tokens |
@source inline(...) |
Safelists classes set dynamically via JS/Alpine |
@layer base |
Inherits primary color from core app theme |
Dark Mode
Dark mode uses the prefix too:
<div class="crm:bg-white crm:dark:bg-gray-900">
<p class="crm:text-gray-900 crm:dark:text-white">
Adapts to dark mode
</p>
</div>
The @custom-variant dark (&:is(.dark *)) directive ensures dark mode activates when the <html> element has the .dark class, matching the core app's behavior.
Dynamic Classes & Safelisting
Tailwind v4 only generates CSS for classes it finds in your source files. Classes added dynamically (e.g., by Alpine.js or Livewire) must be safelisted:
/* Safelist classes that are computed at runtime */
@source inline("crm:bg-green-100 crm:bg-red-100 crm:bg-yellow-100");
@source inline("crm:text-green-800 crm:text-red-800 crm:text-yellow-800");
Common scenarios requiring safelists:
- Status badges with dynamic colors
- Alpine
x-bind:classwith computed values - Livewire conditional class rendering
Vite Configuration
Each module needs its own vite.config.js:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import tailwindcss from '@tailwindcss/vite';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const isDistBuild = process.env.MODULE_DIST_BUILD === 'true';
export default defineConfig({
build: {
outDir: isDistBuild
? path.resolve(__dirname, 'dist/build-crm')
: path.resolve(__dirname, '../../public/build-crm'),
emptyOutDir: true,
manifest: 'manifest.json',
},
plugins: [
laravel({
publicDirectory: isDistBuild
? path.resolve(__dirname, 'dist')
: path.resolve(__dirname, '../../public'),
buildDirectory: 'build-crm',
input: [
path.resolve(__dirname, 'resources/assets/css/app.css'),
path.resolve(__dirname, 'resources/assets/js/app.js'),
],
refresh: true,
}),
tailwindcss(),
],
});
Build Output
| Mode | Output Directory | When |
|---|---|---|
| Development | public/build-{module}/ |
Local dev, hot reload |
| Distribution | modules/{Module}/dist/build-{module}/ |
ZIP packaging for marketplace |
Loading in Blade
@vite([
'resources/assets/css/app.css',
'resources/assets/js/app.js',
], 'build-crm')
Building Module Assets
# From project root (compiles all modules)
npm run dev
# Module-specific compilation via artisan
php artisan module:compile-css CRM --watch # Development with hot reload
php artisan module:compile-css CRM --minify # Production build
php artisan module:compile-css CRM --minify --dist # Distribution build
# From module directory
cd modules/Crm && npm install && npm run build
Common Mistakes
1. Forgetting the Prefix
{{-- WRONG: Classes won't be generated --}}
<div class="py-4 flex gap-2">
{{-- CORRECT: Use module prefix --}}
<div class="crm:py-4 crm:flex crm:gap-2">
2. Prefixing Shared Classes
{{-- WRONG: Shared classes don't have prefix --}}
<button class="crm:btn crm:btn-primary">
{{-- CORRECT: Shared classes are global --}}
<button class="btn btn-primary">
3. Missing Dark Mode Prefix
{{-- WRONG: dark variant needs prefix too --}}
<div class="crm:bg-white dark:bg-gray-900">
{{-- CORRECT: Prefix on both --}}
<div class="crm:bg-white crm:dark:bg-gray-900">
4. Dynamic Classes Not Safelisted
{{-- Alpine sets class dynamically — won't work unless safelisted --}}
<div :class="isActive ? 'crm:bg-green-100' : 'crm:bg-gray-100'">
Add to CSS: @source inline("crm:bg-green-100 crm:bg-gray-100");
Shared Classes Reference
These core classes are available in ALL modules without prefix:
| Category | Classes |
|---|---|
| Buttons | btn, btn-primary, btn-secondary, btn-danger, btn-success, btn-warning, btn-info, btn-default, btn-link, btn-outline-*, btn-sm, btn-lg, btn-icon, btn-icon-primary |
| Forms | form-control, form-label, form-control-textarea, form-control-file, form-control-combobox, form-checkbox, form-input-group |
| Cards | card, card-header, card-body, card-footer, card-title, card-description |
| Badges | badge, badge-primary, badge-success, badge-danger, badge-warning, badge-info, badge-secondary |
| Tables | table, table-responsive, table-thead, table-thead-th, table-tr, table-td |
| Alerts | alert, alert-success, alert-danger, alert-warning, alert-info |
| Typography | page-title, page-description, section-title, prose |
| Links | link, link-secondary, link-danger |
| Layout | ld-container |
Next Steps
- Styling Guide - Complete reference of shared utility classes
- Module Development - Creating and structuring modules
- Theme Development - Building frontend themes