wexample/symfony-design-system

Design system assets for Symfony

Maintainers

Package info

github.com/wexample/symfony-design-system

Language:Twig

pkg:composer/wexample/symfony-design-system

Statistics

Installs: 928

Dependents: 2

Suggesters: 0

Stars: 0

Open Issues: 0

3.0.3 2026-06-13 06:16 UTC

This package is auto-updated.

Last update: 2026-06-13 06:17:37 UTC


README

Version: 3.0.3

Design system assets for Symfony

Table of Contents

Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the Wexample Suite documentation for the complete package ecosystem.

Dependencies

  • php: >=8.2
  • wexample/symfony-loader: >=0.1.0

Versioning & Compatibility Policy

Wexample packages follow Semantic Versioning (SemVer):

  • MAJOR: Breaking changes
  • MINOR: New features, backward compatible
  • PATCH: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Free to use in both personal and commercial projects.

Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the Wexample Suite documentation for the complete package ecosystem.

About us

Wexample stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

Installation

PHP dependencies

Add to composer.json and run composer install:

"wexample/symfony-design-system": "*",
"wexample/symfony-loader": "*",
"wexample/symfony-routing": "*"

Register bundles in config/bundles.php:

Wexample\SymfonyDesignSystem\WexampleSymfonyDesignSystemBundle::class => ['all' => true],
Wexample\SymfonyLoader\WexampleSymfonyLoaderBundle::class => ['all' => true],
Wexample\SymfonyRouting\WexampleSymfonyRoutingBundle::class => ['all' => true],
Wexample\SymfonyTranslations\WexampleSymfonyTranslationsBundle::class => ['all' => true],

Loader configuration

Create config/packages/wexample_symfony_loader.yaml:

wexample_symfony_loader:
    front_paths:
        front: '%kernel.project_dir%/front/'
        WexampleSymfonyDesignSystemBundle: '%kernel.project_dir%/front/'
    default_color_scheme: light  # or dark

Both front and WexampleSymfonyDesignSystemBundle must point to the app's front/ directory so that app templates override DS bundle defaults and translations are scanned correctly.

Routing

Create config/routes/symfony_routing.yaml:

symfony_routing:
    resource: '@WexampleSymfonyRoutingBundle/Resources/config/routes.yaml'

Create config/routes/symfony_loader.yaml:

symfony_loader:
    resource: '@WexampleSymfonyLoaderBundle/Resources/config/routes.yaml'

Services

In config/services.yaml, declare the app home route parameter used by the ds_home_url() Twig function:

parameters:
    wexample_ds_app_home_route: 'your_home_route_name'

JS dependencies

In package.json, add (in addition to the standard encore/webpack stack):

"@wexample/js-api": "*",
"@wexample/js-app": "*",
"@wexample/js-helpers": "*",
"@wexample/symfony-api": "file:vendor/wexample/symfony-api/assets",
"@wexample/symfony-design-system": "file:vendor/wexample/symfony-design-system/assets",
"@wexample/symfony-loader": "file:vendor/wexample/symfony-loader/assets",
"@emoji-mart/data": "^1.2.1",
"@fortawesome/free-brands-svg-icons": "*",
"@fortawesome/free-solid-svg-icons": "*",
"ajv": "*",
"emoji-mart": "*",
"fos-router": "file:vendor/friendsofsymfony/jsrouting-bundle/Resources",
"glob": "*",
"prismjs": "*",
"vue": "^3",
"vue-loader": "*",
"webpack-virtual-modules": "*"

Webpack config

In webpack.config.mjs, use buildEncoreConfig from the loader. If the Node container does not have PHP available, bypass the PHP build hooks:

import { buildEncoreConfig } from './vendor/wexample/symfony-loader/src/Resources/js/webpack/encore.manifest.js';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
const FosRouting = require('./vendor/friendsofsymfony/jsrouting-bundle/Resources/webpack/FosRouting');

const config = buildEncoreConfig({
    clearCache: false,
    generateEncoreManifest: false,
    dumpFosRoutes: false,
});

// Replace FosRouting plugin to skip PHP compilation hooks
const fosIdx = config.plugins.findIndex(p => p.constructor?.name === 'FosRouting');
if (fosIdx !== -1) {
    config.plugins.splice(fosIdx, 1, new FosRouting({}, false));
}

export default config;

Pre-generate the PHP artifacts from the PHP container before running webpack (see watch script below).

tsconfig.json

{
    "ts-node": { "ignore": ["/node_modules/(?!@wexample/)"] },
    "compilerOptions": {
        "target": "ES6",
        "module": "ESNext",
        "moduleResolution": "bundler",
        "baseUrl": ".",
        "paths": {
            "@front/*": ["./front/*"],
            "@WexampleSymfonyDesignSystemBundle/*": ["./front/*"],
            "@wexample/symfony-api/*": ["./vendor/wexample/symfony-api/assets/*"],
            "@wexample/symfony-design-system/*": ["./vendor/wexample/symfony-design-system/assets/*"],
            "@wexample/symfony-loader/*": ["./vendor/wexample/symfony-loader/assets/*"]
        }
    }
}

The ts-node.ignore pattern allows ts-node to process @wexample TypeScript packages during webpack config loading.

Note: tsconfig.json is partially overwritten by php bin/console loader:generate-encore-manifest. Only the ts-node block and manually added path aliases survive. Run the command first, then add custom paths.

Watch script (split PHP/Node containers)

If PHP and Node run in separate containers, create a host-side orchestration script (e.g. .wex/bash/watch.sh):

docker exec -i "$CONTAINER_FRANKENPHP" php bin/console cache:clear --no-warmup
docker exec -i "$CONTAINER_FRANKENPHP" php bin/console loader:generate-encore-manifest
docker exec -i "$CONTAINER_FRANKENPHP" php bin/console fos:js-routing:dump --target=var/cache/fosRoutes.json --format=json
docker exec -it "$CONTAINER_NODE" /bin/sh -c "cd $APP_DIR && yarn watch"

The package.json watch script is the direct encore command; the shell script is the host-level orchestration.

Private layout

Create front/layouts/private/layout.html.twig extending the DS dashboard layout:

{%- extends '@WexampleSymfonyDesignSystemBundle/layouts/dashboard/layout.html.twig' -%}

{%- block layout_config -%}
    {{- render_pass.layoutRenderNode.setDefaultView(_self) -}}
    {{ parent() }}
{%- endblock -%}

Add the sidebar menu and page structure blocks as needed. See the DS bundle's layouts/design_system/layout.html.twig for the menu pattern using menu_get_routes_from_controller_namespace.

Create front/layouts/private/layout.ts to instantiate the JS app:

import App from '@wexample/symfony-loader/js/Class/App';
import AppService from '@wexample/symfony-loader/js/Class/AppService';
import VueService from '@wexample/symfony-loader/js/Services/VueService';
import IconService from '@wexample/symfony-loader/js/Services/IconService';
import ToastService from '@wexample/symfony-loader/js/Services/ToastService';
import ConfirmService from '@wexample/symfony-loader/js/Services/ConfirmService';
import KeyboardService from '@wexample/symfony-loader/js/Services/KeyboardService';
import ModalService from '@wexample/symfony-loader/js/Services/ModalService';

class AppCustom extends App {
    getServices(): (typeof AppService | [typeof AppService, any[]])[] {
        return [
            ...super.getServices(),
            VueService, IconService, ToastService,
            ConfirmService, KeyboardService, ModalService,
        ];
    }
}

new AppCustom();

Create front/layouts/private/layout.en.yml with at minimum:

layout:
  logo:
    alt: Your app name

Color palette

Create front/css/partials/_palette.scss to override DS bundle defaults:

$colorPrimary: #your-color;
$colorSecondary: #your-color;
$colorAccent: #your-color;
$colorBlack: #000000;

The DS bundle provides assets/css/partials/_palette.scss with !default values that this file overrides.

App design system controller

Create src/Controller/DesignSystem/AppController.php to expose the /_design_system/app/ route:

#[Route(name: 'app_design_system_app_', path: AbstractDesignSystemController::CONTROLLER_BASE_ROUTE . '/app/')]
final class AppController extends AbstractAppController
{
    #[Route(name: 'index', path: '')]
    public function index(): Response
    {
        return $this->renderPage('index');
    }
}

Template at front/design_system/app/index.html.twig (path mirrors the controller namespace, stripping App\Controller\).

Known issues / TODOs

  • Translations overwrite bug: WexampleSymfonyTranslationsExtension used to overwrite translations_paths instead of merging, erasing paths set by WexampleSymfonyLoaderExtension. Fixed by merging in the translations extension. Verify this is resolved in your version.
  • TODO: Document how to add additional app-specific DS pages beyond app/index.
  • TODO: Document the has_simple_routes / has_template_routes service tags and when #[TemplateBasedRoutes] is sufficient vs explicit route declarations.

Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.