Skip to content

Shopware 6 Theme Development: SCSS, Twig Overrides, and Storefront Customizations

Published on Jun 25, 2025 | approx. 1 min read |

The Shopware 6 Storefront is built on Bootstrap 5 and Twig. Themes are developed as special plugins and use an elegant override system: instead of copying and modifying files, you selectively override only the parts that need to change.

Theme Base Structure

A theme is a special plugin with a theme.json and the Theme trait:

MyTheme/
├── composer.json
├── src/
│   ├── MyTheme.php               # Plugin class with ThemeInterface
│   └── Resources/
│       └── theme.json            # Theme configuration
│       └── app/
│           └── storefront/
│               ├── src/
│               │   ├── scss/
│               │   │   └── base.scss     # SCSS entry point
│               │   └── js/
│               │       └── my-theme.js   # JS entry point
│               └── views/
│                   └── storefront/       # Twig overrides

Plugin Class

<?php

declare(strict_types=1);

namespace MyTheme;

use Shopware\Core\Framework\Plugin;
use Shopware\Storefront\Framework\ThemeInterface;

class MyTheme extends Plugin implements ThemeInterface
{
}

theme.json

{
    "name": "MyTheme",
    "author": "Wunner Software",
    "description": {
        "en-GB": "A custom Shopware 6 theme",
        "de-DE": "Ein Shopware 6 Custom Theme"
    },
    "views": ["@Storefront", "@Plugins", "@MyTheme"],
    "style": ["@Storefront", "app/storefront/src/scss/base.scss"],
    "script": ["@Storefront", "app/storefront/src/js/my-theme.js"],
    "asset": ["app/storefront/src/assets"],
    "config": {
        "blocks": {
            "colors": {
                "label": {
                    "en-GB": "Colors",
                    "de-DE": "Farben"
                },
                "fields": {
                    "sw-color-brand-primary": {
                        "label": {
                            "en-GB": "Primary color",
                            "de-DE": "Primärfarbe"
                        },
                        "type": "color",
                        "value": "#1a365d",
                        "editable": true
                    }
                }
            }
        }
    }
}

SCSS Customization

The Shopware Storefront uses Bootstrap 5. The cleanest way to customize styles is by overriding SCSS variables before Bootstrap is loaded.

base.scss — Overriding Variables

// Custom variables BEFORE the Storefront import
$primary: #1a365d;
$secondary: #3182ce;
$font-family-base: 'Inter', system-ui, sans-serif;
$border-radius: 0.375rem;

// Override Shopware SCSS variables
$sw-color-brand-primary: $primary;
$sw-color-brand-secondary: $secondary;

// Custom styles — the Storefront base is included via theme.json (see below)
.my-custom-component {
    background: $primary;
    color: white;
    padding: 1rem;
    border-radius: $border-radius;
}

Organizing Custom SCSS Partials

// base.scss — Storefront base is controlled via theme.json, not via @import
@import "variables";
@import "components/header";
@import "components/product-card";
@import "components/checkout";
@import "pages/product-detail";
@import "pages/listing";

Twig Override System

Shopware uses a Twig namespace system. @Storefront refers to the original Storefront templates. To override a template, create a file at the same position within your own theme.

Replacing a Template Entirely

To override /vendor/shopware/storefront/Resources/views/storefront/component/product/card/box.html.twig:

MyTheme/src/Resources/views/storefront/component/product/card/box.html.twig

Overriding a Single Block (Cleaner Approach)

{# File: views/storefront/component/product/card/box.html.twig #}
{% sw_extends '@Storefront/storefront/component/product/card/box.html.twig' %}

{% block component_product_box_image %}
    <div class="my-custom-image-wrapper">
        {{ parent() }}
        <span class="badge badge-custom">NEU</span>
    </div>
{% endblock %}

sw_extends is the Shopware-specific extend tag that respects the theme inheritance system. parent() renders the original block content.

Understanding the Template Hierarchy

When theme.json contains "views": ["@Storefront", "@Plugins", "@MyTheme"], templates are resolved in this order during rendering. Your own theme has the highest priority.

Storefront JavaScript

Shopware uses its own plugin system for JavaScript (not to be confused with PHP plugins). Each interactive component is registered as a Storefront JS plugin.

// my-plugin.js
import Plugin from 'src/plugin-system/plugin.class';

export default class MyPlugin extends Plugin {
    static options = {
        animationDuration: 300,
    };

    init() {
        this._registerEvents();
    }

    _registerEvents() {
        this.el.addEventListener('click', this._onClick.bind(this));
    }

    _onClick(event) {
        event.preventDefault();
        this.el.classList.toggle('active');
    }
}

Registering the plugin:

// my-theme.js
import MyPlugin from './my-plugin';

const PluginManager = window.PluginManager;
PluginManager.register('MyPlugin', MyPlugin, '[data-my-plugin]');

Setting the data attribute in the Twig template:

<div data-my-plugin="true">
    <!-- Content -->
</div>

Compiling and Activating the Theme

# Install the theme
php bin/console plugin:install --activate MyTheme

# Compile the theme (SCSS + JS)
php bin/console theme:compile

# Assign the theme to a sales channel (via admin panel or CLI)
php bin/console theme:change --all MyTheme

In development mode with a watcher:

# Watch mode for SCSS and JS — run from the project root
composer run watch:storefront
# or with the production template:
./bin/watch-storefront.sh

Common Pitfalls

1. Cache not cleared: Always run bin/console cache:clear after template changes.

2. sw_extends instead of extends: In Shopware, you must use sw_extends for the theme override system to work correctly.

3. Bootstrap version: Shopware 6.5+ uses Bootstrap 5, older versions (6.4 and earlier) use Bootstrap 4. Variable names differ (e.g. $primary vs. $theme-primary).

4. Asset cache: After changing assets (images, fonts), run bin/console asset:install and clear the Varnish/browser cache.

Conclusion

Shopware themes are well-structured and offer an elegant way to customize only the necessary parts through the block override system. The Twig inheritance system with sw_extends and parent() enables clean, maintainable customizations without copy-pasting entire templates.

Thomas Wunner

Thomas Wunner

Certified IT specialist for application development with an instructor qualification and over 14 years of experience building scalable web applications with Symfony and Shopware. When not coding, Thomas volunteers as a lifeguard with the Wasserwacht, performs as a DJ, and explores the countryside on his motorbike.

Comments

Comments are provided by Remark42. By loading comments, data is transmitted to our comment server.