Tailwind CSS
Publica.la runs on Tailwind CSS v3 — see the official v3 documentation for full reference.
Basic configuration
The main configuration file is tailwind.config.js. We use the tw- prefix to avoid class name collisions with Bootstrap while both systems coexist.
// tailwind.config.js
module.exports = {
prefix: 'tw-',
content: [
'./resources/views/**/*.blade.php',
'./resources/js/**/*.js',
],
theme: {
extend: {
colors: {
primary: {
600: '#7C3AED',
},
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
},
},
plugins: [require('@tailwindcss/typography')],
}
Tip: always list your Blade (
.blade.php) and Vue/JS files in thecontentarray; otherwise PurgeCSS will drop the classes.
Developer workflow
| Action | Command |
|---|---|
| One-off build | zex yarn dev |
| Watch & rebuild | zex yarn watch |
| Build email CSS | zex yarn tailwind-mail |
Problem: “My class does not apply”
Quick checklist:
- Is the view path included in the
contentarray? - Does the class have the
tw-prefix? - Are you running
watch? Save the file and check again.
Email CSS
Emails use a separate build:
zex yarn tailwind-mail
The command generates resources/views/vendor/mail/html/themes/tailwind.css, ready to be inlined by Blade. Commit the generated file.
Accessibility helpers
Follow the focus utilities defined in @tailwind-css-guidelines.mdc:
<button
class="tw-rounded tw-px-4 tw-py-2 focus-visible:tw-outline-none
focus-visible:tw-ring-4 focus-visible:tw-ring-violet-600/50">
Buy now
</button>
Migrating from Bootstrap 4
| Bootstrap class | Tailwind replacement |
|---|---|
mt-3 | tw-mt-3 |
d-flex | tw-flex |
text-center | tw-text-center |
Recommendations:
- Open small PRs per module.
- Avoid arbitrary values unless strictly necessary (
tw-w-[72px]). - Prefer Blade components to avoid duplicate markup.
Advanced troubleshooting
- False PurgeCSS positives: when you generate dynamic classes, whitelist them in
safelistor create explicit variants.
Build tools
The current asset pipeline relies on Laravel Mix (via the mix() helper and the custom asset_from_cdn() wrapper). A migration to Vite is planned; once complete you should use @vite() instead of mix() and asset_from_cdn() will be updated accordingly.
Last updated: 2025-07-14