itech-world / sulu-tailwind-theme-bundle
Complete theming system for Sulu CMS 3.x based on design tokens compiled to CSS custom properties
Package info
github.com/steeven-th/SuluTailwindThemeBundle
Language:Twig
Type:sulu-bundle
pkg:composer/itech-world/sulu-tailwind-theme-bundle
Requires
- php: ^8.2
- doctrine/doctrine-bundle: ^2.11
- doctrine/orm: ^3.0
- sulu/sulu: ^3.0
- symfony/framework-bundle: ^7.0
Requires (Dev)
- phpunit/phpunit: ^10.0
- symfony/debug-bundle: ^7.0
This package is auto-updated.
Last update: 2026-03-05 15:17:25 UTC
README
Tailwind Theme Bundle
Complete theming system for Sulu CMS 3.x
A design-token-based theming system that compiles JSON configuration into CSS custom properties.
Manage colors, typography, buttons, borders, block variants, and menu styles from the Sulu admin interface.
See screenshots of the admin interface
Requirements
- PHP >= 8.2
- Sulu CMS >= 3.0
- Doctrine ORM >= 3.0
- Tailwind CSS >= 4.0
- Webpack Encore
Features
- Design tokens: Store all theme settings as structured JSON, compiled to CSS custom properties
- Admin interface: Full CRUD with 7 tabs (details, colors, typography, buttons, borders, block variants, menu)
- Multiple themes: Create and switch between 7 preset themes (corporate, creative, minimal, nature, halloween, christmas, megamenu)
- CSS compilation: Automatic generation of
:rootvariables,.block-variant-*classes,.btn-*styles - Google Fonts: Automatic resolution and inclusion of Google Fonts from typography settings
- Block variants: Per-block color schemes (light, accent, dark) applied via CSS custom properties
- Menu configuration: Configurable menu type, colors, animation, and display options
- Twig integration: Helper functions for including theme CSS, fonts, block styles, and menu config
- CLI commands: Install preset themes and recompile CSS from the command line
- Auto-recompile: Doctrine listener recompiles CSS on theme save
Installation
1. Require the bundle
composer require itech-world/sulu-tailwind-theme-bundle
For local development with a path repository, add to your project's composer.json:
{
"repositories": [
{
"type": "path",
"url": "../SuluTailwindThemeBundle"
}
],
"require": {
"itech-world/sulu-tailwind-theme-bundle": "dev-dev"
}
}
2. Register the bundle
If Symfony Flex doesn't register it automatically, add to config/bundles.php:
return [ // ... ItechWorld\SuluTailwindThemeBundle\ItechWorldSuluTailwindThemeBundle::class => ['all' => true], ];
3. Register routes
Add the following to your config/routes.yaml:
itech_world_sulu_tailwind_theme: resource: '@ItechWorldSuluTailwindThemeBundle/src/Controller/' type: attribute
4. Register frontend assets
The bundle provides Stimulus controllers and CSS that need to be compiled by Webpack Encore.
Add the npm package to your project's package.json:
{
"devDependencies": {
"@itech-world/sulu-tailwind-theme-bundle": "file:vendor/itech-world/sulu-tailwind-theme-bundle/assets"
}
}
Import the CSS and add the bundle's templates as a Tailwind source in your assets/styles/app.css:
@import "@itech-world/sulu-tailwind-theme-bundle"; @source "../../vendor/itech-world/sulu-tailwind-theme-bundle/templates";
The
@sourcedirective tells Tailwind CSS 4 to scan the bundle's Twig templates for utility classes. Without it, classes used in menu and block templates won't be compiled.
Register the Stimulus controllers in your assets/controllers.json:
{
"controllers": {
"@itech-world/sulu-tailwind-theme-bundle": {
"lightbox": {
"enabled": true,
"fetch": "lazy"
},
"menu": {
"enabled": true,
"fetch": "lazy"
},
"slider": {
"enabled": true,
"fetch": "lazy"
},
"carousel3d": {
"enabled": true,
"fetch": "lazy"
},
"key_figures": {
"enabled": true,
"fetch": "lazy"
},
"location_overlay": {
"enabled": true,
"fetch": "lazy"
}
}
},
"entrypoints": []
}
Configure Webpack to disable symlink resolution in your webpack.config.js:
// Replace the last line: // module.exports = Encore.getWebpackConfig(); // With: const config = Encore.getWebpackConfig(); config.resolve.symlinks = false; module.exports = config;
This is required so that Webpack treats the bundle's Stimulus controllers as
node_modulesfiles (skipping Babel transpilation) and resolves their dependencies correctly.
Then install and rebuild your assets:
npm install npm run build
5. Register admin assets
Edit the assets/admin/package.json to add the bundle to the list of bundles:
{
"dependencies": {
// ...
"sulu-itech-world-sulu-tailwind-theme-bundle": "file:../../vendor/itech-world/sulu-tailwind-theme-bundle/public/js"
}
}
Edit the assets/admin/app.js to add the bundle in imports:
import 'sulu-itech-world-sulu-tailwind-theme-bundle';
In the assets/admin/ folder, run the following command:
npm install npm run build
or
yarn install yarn build
6. Update the database schema
php bin/adminconsole doctrine:schema:update --force
7. Install a preset theme (optional)
php bin/adminconsole iw-sulu:theme:install corporate
Available presets: corporate, creative, minimal, nature, halloween, christmas, megamenu.
8. Clear the cache
php bin/adminconsole cache:clear
Configuration
The bundle works with zero configuration. The only optional setting is the Google Fonts API key for the Font Picker autocomplete.
Google Fonts API key (optional)
The typography tab includes a Font Picker with autocomplete for Google Fonts. To enable it:
-
Get an API key from the Google Cloud Console:
- Create a project (or use an existing one)
- Enable the Google Fonts Developer API in API Library
- Create an API key in Credentials
- (Recommended) Restrict the key to the Google Fonts Developer API only
-
Add the key to your
.envfile:GOOGLE_FONTS_API_KEY=your_api_key_here
-
Configure the bundle in
config/packages/itech_world_sulu_tailwind_theme.yaml:itech_world_sulu_tailwind_theme: google_fonts_api_key: '%env(GOOGLE_FONTS_API_KEY)%'
-
Sync the font catalog (first time or to update):
php bin/adminconsole iw-sulu:theme:sync-fonts
You can also sync from the admin UI by clicking the sync button (↻) in the Font Picker.
Without an API key, the Font Picker still works: the Google tab falls back to a free-text input, and the System tab lists 15 cross-platform fonts (Arial, Georgia, Courier New, etc.).
Usage
Admin interface
Navigate to Settings > Themes in the Sulu admin panel. From there you can:
- Create a theme: Click "Add", fill in the name and label
- Configure colors: Set primary, secondary, accent, and background colors + text, link, and link hover colors
- Configure typography: Select fonts for headings/body/accent via the Font Picker (Google Fonts autocomplete, system fonts, or free text)
- Configure buttons: Set primary/secondary/accent button styles (background, text, border, hover states, radius)
- Configure borders: Set border radius values (default, small, large, full, image)
- Configure block variants: Define color schemes (e.g., light, accent, dark) for content blocks
- Configure menu: Choose menu type, colors, animation, and display options
- Activate: Toggle the
isActiveflag to make a theme the active one
Page templates
The bundle ships with a ready-to-use page template (iw_theme_default) that includes 11 block types: text, text_images, gallery, key_figures, linked_pages, location, form, document, cta, testimonial, and separator.
To use it, simply select "Page par défaut" (or "Default page") as the template when creating a page in the Sulu admin.
The template system uses a modular architecture with global block types registered via sulu_admin.templates.block.directories. You can create your own page templates referencing any subset of blocks, use XInclude fragments to reuse shared properties, and exclude the default template from specific webspaces.
See Page Templates for the full reference: modular architecture, creating custom templates, available block types, XInclude fragments, and excluding templates.
Integrating the theme in your base template
Add the theme functions to your templates/base.html.twig:
<head> {# Google Fonts #} {{ iw_sulu_tailwind_theme_fonts_link()|raw }} {# Compiled CSS custom properties #} {% set themeCssPath = iw_sulu_tailwind_theme_css_path() %} {% if themeCssPath is not empty %} <link rel="stylesheet" href="{{ themeCssPath }}"> {% endif %} {{ encore_entry_link_tags('app') }} </head> <body class="bg-[var(--color-background)] text-[var(--color-text)]"> {# Dynamic menu #} {% set menuConfig = iw_sulu_tailwind_theme_menu_config() %} {% if menuConfig is not empty and menuConfig.type is defined %} {% include '@ItechWorldSuluTailwindTheme/menu/_' ~ menuConfig.type ~ '.html.twig' with {config: menuConfig} %} {% endif %} {% block content %}{% endblock %} {{ encore_entry_script_tags('app') }} </body>
The bundle also provides
@ItechWorldSuluTailwindTheme/base.html.twigas a ready-to-extend base template. See Custom Integration Guide for a complete example with SEO, fallback navigation, and more.
Twig functions
| Function | Returns |
|---|---|
iw_sulu_tailwind_theme_css_path() |
Web path to the compiled theme CSS |
iw_sulu_tailwind_theme_fonts_link() |
<link> tags for Google Fonts |
iw_sulu_tailwind_theme_menu_config() |
Menu configuration array |
iw_sulu_tailwind_theme_tokens() |
Full design tokens array |
iw_sulu_tailwind_theme_block_styles() |
Block style configuration |
iw_sulu_block_style_template(type, style) |
Resolved template path for a block style |
The global variable iw_sulu_tailwind_theme is available in all templates and contains the active theme tokens.
See Twig Reference for the full API, return types, and token structure.
CLI commands
# Install a preset theme and activate it php bin/adminconsole iw-sulu:theme:install <preset-name> # Recompile CSS for the active theme (or a specific one) php bin/adminconsole iw-sulu:theme:compile php bin/adminconsole iw-sulu:theme:compile --theme=corporate # Sync the Google Fonts catalog (requires API key) php bin/adminconsole iw-sulu:theme:sync-fonts
Security
The bundle registers the security context sulu.iw_sulu_tailwind_theme.themes with VIEW, ADD, EDIT, and DELETE permissions. Configure role access in Settings > Roles.
Documentation
The theme compiles design tokens into CSS custom properties and exposes data through Twig functions and a global variable. Your custom templates and CSS automatically adapt when the active theme changes.
| Document | Description |
|---|---|
| Screenshots | Visual overview of the admin interface (colors, typography, buttons, blocks, menu) |
| Page Templates | Modular architecture, creating custom templates, block types, XInclude fragments |
| CSS Variables Reference | All CSS custom properties: colors, palettes, typography, borders, buttons, menu |
| Block Variants | Variant classes, auto-styled elements, separator styles, .btn-variant |
| Twig Reference | All Twig functions, global variable iw_sulu_tailwind_theme, token structure |
| Custom Integration Guide | Custom CSS, Twig components, block templates, PHP services, Tailwind integration |
| Menus | Menu types, configuration, and customization |
Architecture
SuluTailwindThemeBundle/
├── config/
│ ├── forms/ # Sulu admin form XMLs (7 tabs)
│ ├── lists/ # Sulu admin list XML
│ ├── templates/
│ │ ├── pages/ # Page template XML (uses <type ref="..."/>)
│ │ ├── blocks/ # Global block type definitions (11 types)
│ │ └── fragments/ # Shared property fragments (reference)
│ └── services.yaml # Service definitions
├── src/
│ ├── Admin/ # ThemeAdmin (navigation, views, security)
│ ├── Command/ # CLI commands (install, compile, sync-fonts)
│ ├── Controller/Admin/ # REST API controller
│ ├── DataFixtures/ # Preset theme fixtures
│ ├── Entity/ # ThemeConfig Doctrine entity
│ ├── EventSubscriber/ # Auto-recompile on save
│ ├── Repository/ # ThemeConfigRepository
│ ├── Service/ # ThemeCompiler, ThemeProvider, GoogleFontsResolver, GoogleFontsCatalog
│ └── Twig/ # ThemeExtension
├── templates/ # Twig templates (blocks, menus, base)
├── translations/ # Admin translations (fr, en, de)
├── assets/ # Frontend assets (Stimulus controllers, CSS)
└── public/js/ # Admin React components
Available translations
- English
- French
- German
🐛 Bug and Idea
See the open issues for a list of proposed features (and known issues).
💰 Support me
You can buy me a coffee to support me this plugin is 100% free.
👨💻 Contact
📘 License
This bundle is under the MIT License.

