---
title: Custom Storefront Javascript | Shopware Community Hub
description: >-
  Getting started with adding custom storefront JavaScript to change and extend
  the behavior of your Shopware shop.
canonical_url: 'https://hub.shopware.com/learn/unit/custom-javascript'
---

# Custom Storefront Javascript

<LearningObjectives>

- Understand the storefront JavaScript plugin system in Shopware.
- Know the folder structure for custom storefront JavaScript.
- Learn how to add custom storefront JavaScript to your shop.
- Learn how to override existing storefront JavaScript plugins.
- Understand the difference between synchronous and asynchronous storefront JavaScript plugins.

</LearningObjectives>

# Custom Storefront Javascript

Styling your shop is great, but sometimes you need to change the **behavior** of your shop as well. This is where **storefront JavaScript** comes into play.

In this learning unit, we will learn how to add custom storefront JavaScript to your Shopware shop.

<Callout title="Storefront vs. Administration JavaScript" type="info">

Shopware has two main JavaScript layers:

- **Storefront JavaScript** controls the behavior and interactivity of the **Shopware storefront** (what the customer sees).
- **Administration JavaScript** extends and customizes the **Shopware Admin panel** (what shop owners and managers see).

In this learning path, we will focus on the **storefront JavaScript**. The **administration JavaScript** will be covered in the next learning path.

</Callout>

## Storefront JavaScript in Shopware

In Shopware, storefront JavaScript is integrated through a **custom JavaScript plugin system** built by Shopware. This system provides a clear structure for writing and organizing your custom JavaScript code in a maintainable way. For that, Shopware provides its **PluginManager**, which is responsible for loading JavaScript plugins. With it, you can add (**register**) new features or extend (**override**) existing features in a structured way without breaking the Shopware 6 JavaScript core.

Shopware storefront JavaScript uses **modern ES6+ features** (e.g., `import`, `export`, `class`, `async/await`). This means you can write your code in any modern JavaScript way, and Shopware ensures the compatibility with all major browsers.

<Callout title="Important: jQuery Removed From Shopware 6.5+ core" type="warning">

Since Shopware version 6.5, **jQuery** is no longer used in Shopware JavaScript core ([read here](https://github.com/shopware/shopware/blob/trunk/UPGRADE-6.5.md#javascriptjquery)).
If you are using jQuery in your JavaScript plugins, you need to migrate to **vanilla JavaScript**. If you need jQuery for legacy plugins, you have to include it by adding the following line to your plugin:

```twig
{% sw_extends '@Storefront/storefront/base.html.twig' %}

{% block base_body_script %}
    {{ parent() }}
    <!-- Include jQuery here -->
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
{% endblock %}
```

</Callout>

## Getting Started: GitHub, CLI, or From Scratch

If you are already quite familiar with JavaScript and Shopware, you might want to write your code from scratch. If you are a beginner, it is recommended to use a Shopware console command to generate a new storefront JavaScript plugin. Or you can use the example plugin from the documentation [here](https://github.com/ShopwareAcademy/AcademyCustomJs) to get a quick start.

### GitHub

We will always start from your Shopware root directory in all of our development examples. This saves us lots of comments and explanations.

```shell
cd custom/plugins
git clone git@github.com:ShopwareAcademy/AcademyCustomJs.git
cd AcademyCustomJs
git checkout LU-02-custom-js-add
```

### CLI

With the Shopware console command `bin/console plugin:create`, you can be sure that all necessary files are created in the correct location. Run the following command in your Shopware root directory:

```shell
bin/console plugin:create AcademyCustomJs
```

This command will create a new plugin called `AcademyCustomJs` in the `[your_shop_root]/custom/plugins` directory. During the interactive setup, you can choose the example storefront JavaScript plugin to get a better understanding of how a plugin is structured.

```shell
Do you want to create an example javascript plugin? (yes/no) [yes]:
```

Whenever you create the plugin using the CLI or clone it, you need to refresh the plugin list and install the plugin:

```shell
bin/console plugin:refresh
bin/console plugin:install AcademyCustomJs --activate
```

<Callout title="Create a JavaScript Plugin Only" type="info">

You can also create a JavaScript plugin in an **existing** plugin by running the following command in your Shopware root directory:

```bash
bin/console make:plugin:javascript-plugin
```

When executing this command, you will be asked to choose the name of the plugin in which you want to generate the JavaScript plugin.

</Callout>

## File and Folder Structure

The basic file and folder structure of a storefront JavaScript plugin looks like:

```txt
└── custom
    └── plugins
        └── AcademyCustomJs
            ├── src
            │   └── Resources
            │       └── app
            │           └── storefront
            │               └── src
            │                │── example-plugin
            │                │  └── example-plugin.plugin.js
            │                └── main.js // <-- Entry point
            └── composer.json
```

All storefront JavaScript files are located in the `<Plugin root>/src/Resources/app/storefront/src` directory. In this case `AcademyCustomJs/src/Resources/app/storefront/src` or the full path from your shop root directory it is `[your_shop_root]/custom/plugins/AcademyCustomJs/src/Resources/app/storefront/src`.

### The `main.js` File

The `main.js` file is the entry point of your storefront JavaScript plugin (similar to the `base.scss` file for SCSS). The `main.js` is used to load your custom JavaScript plugins by using the `PluginManager` to register a new plugin with the Shopware storefront.

```js
// Import all necessary Storefront plugins
import ExamplePlugin from './example-plugin/example-plugin.plugin';

// Register your plugin via the existing PluginManager
const PluginManager = window.PluginManager;

PluginManager.register('ExamplePlugin', ExamplePlugin, '[data-example-plugin]');

```

The `PluginManager.register` takes three arguments:

- Plugin name: A unique name for the plugin.
- Plugin class: The class that defines the plugin's behavior.
- Selector (optional): A [CSS selector](https://www.w3schools.com/cssref/css_selectors.php) that tells which HTML element this plugin should be attached to. This means you can add the class name, the ID, or attributes of an HTML element to "link" storefront JavaScript plugins to specific HTML elements.

### The `example-plugin.plugin.js` File

The `example-plugin.plugin.js` file is the main file of your storefront JavaScript plugin. This is where you write your JavaScript code.

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

export default class ExamplePlugin extends Plugin {
    init() {
        window.addEventListener('scroll', this.onScroll.bind(this));
        console.log('Hello from the example plugin');
    }

    onScroll() {
        if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
            alert('Seems like there\'s nothing more to see here.');
        }
    }
}

```

Every custom storefront JavaScript plugin needs to extend the `Plugin` class. This class provides a lot of useful methods and properties that you can use to write your own storefront JavaScript plugins.

Every storefront JavaScript plugin has the `init()` method, which is called when the plugin is initialized, so it is the "execution point." In this method, you can add event listeners, add custom functionality, or do anything else you want.

### Linking the Storefront JavaScript Plugin to the Template

To test the storefront JavaScript plugin, we need to link (register) it to the storefront. For our simple test, we did it with the custom data attribute `[data-example-plugin]`. Now Shopware will look for this attribute in the HTML and attach the storefront JavaScript plugin to the element.

If you create the plugin with the Shopware console command, you will find the custom data attribute in the following location:

```txt
└── custom
    └── plugins
        └── AcademyCustomJs
            ├── src
            │   └── Resources
            │       └── views
            │           └── storefront
            │               └── page
            │                   └── content
            │                       └── index.html.twig // <-- Here
            └── ...
```

The `index.html.twig` file should contain the following code:

```twig
{% sw_extends '@Storefront/storefront/page/content/index.html.twig' %}

{% block base_main_inner %}
    {{ parent() }}

    <template data-example-plugin></template>
{% endblock %}
```

You see the `template` element, which has the custom data attribute `data-example-plugin`. We used this attribute to link the storefront JavaScript plugin to this element in the storefront. This way, you decide which elements in the storefront should have encapsulated functionality.

The **`template`** element is a neutral container that does not render any visible content by default. This makes it ideal for linking storefront JavaScript plugins because you can safely attach behavior without adding extra markup to your HTML.

However, you can also use any other HTML element (`div`, `span`, `button`, etc.) to link your storefront JavaScript plugin to something visible on the page. The important part is that the selector (class, ID, or attribute) is registered correctly in the `main.js` file.

### Storefront Behavior: Example From the GitHub Repository

If you are using the **GitHub repository**, the compiled sources under the `dist` folder (`custom/plugins/AcademyCustomJs/src/Resources/app/storefront/dist/storefront/js/academy-custom-js/academy-custom-js.js`) should already be present.

Now, when you scroll to the bottom of the startpage in your shop, you should see the alert.

![Alert on homepage](assets/javascriptPluginAlert.jpg)

## Building the Storefront

### The `bin/build-storefront.sh` Command

If you are working on the **plugin from scratch**, you need to build the storefront first. Run the following command in your Shopware root directory:

```shell
bin/build-storefront.sh
```

### The `dist` Folder

If you run the **`bin/build-storefront.sh`** command, the `dist` folder will be created. This folder contains all compiled files for the storefront that Shopware loads.

In short:

- You write your storefront JavaScript plugins in the `src` folder.
- Then run `bin/build-storefront.sh` in your Shopware root directory.
- Shopware loads your compiled/updated storefront JavaScript from the **`dist`** folder.

### The `bin/watch-storefront.sh` Command

Shopware provides a **`bin/watch-storefront.sh`** command that starts a development server. It **recompiles storefront JavaScript and SCSS automatically** when you make file changes, so you don't have to manually run the build-storefront.sh script after every change.

```shell
bin/watch-storefront.sh
```

This is very useful for development, but it does **not** build the storefront and does **not** update the `dist` folder. For that you need to run the `bin/build-storefront.sh` manually.

## Extending an Existing Plugin

A more day-to-day example for storefront JavaScript plugins is to extend an existing plugin. For example, you might want to add a new feature to the `AddToCartPlugin` or overwrite an existing feature.

The offcanvas cart is a good example of this, some shops do not want to show the offcanvas cart when a product is added to the cart. For instance, to avoid distractions for the customer or to make the checkout process quicker (for deals that are only available for a short time).

<Callout title="Existing Storefront Plugins" type="info">

Shopware provides many storefront JavaScript plugins in its core for the storefront. You can find them in this [doc](https://developer.shopware.com/docs/resources/references/storefront-reference/plugin-reference.html).

</Callout>

### Example: AddToCartPlugin

To extend the `AddToCartPlugin` you can create a new plugin that extends the existing one. This way you can overwrite the existing methods and add new ones.

#### Create a New Folder and File

```txt
└── custom
    └── plugins
        └── AcademyCustomJs
            ├── src
            │   └── Resources
            │       └── app
            │           └── storefront
            │               └── src
            │                │── example-plugin
            │                │  └── example-plugin.plugin.js
            │                │── custom-add-to-cart // <-- New folder
            │                │  └── custom-add-to-cart.plugin.js // <-- New file
            │                └── main.js // <-- Entry point
            └── composer.json
```

You see that we created a new folder `custom-add-to-cart` and a new file `custom-add-to-cart.plugin.js`.

Now we want to override the **`_openOffCanvasCart`** method to prevent the offcanvas cart from opening.

```js
import AddToCartPlugin from 'src/plugin/add-to-cart/add-to-cart.plugin';

export default class CustomAddToCartPlugin extends AddToCartPlugin {
    _openOffCanvasCart() {
        // Override the method to prevent opening the offcanvas cart
        console.log('Item added to cart without opening offcanvas');
    }

}
```

You see that we import the `AddToCartPlugin` from the `src/plugin/add-to-cart/add-to-cart.plugin` file instead the plugin `import Plugin from 'src/plugin-system/plugin.class'`. This file contains the original `AddToCartPlugin` class that we want to override/extend. The `AddToCartPlugin` has the `_openOffCanvasCart` method. We override this method by creating a new method with the same name.

<Callout title="Extending instead of overriding" type="info">

If you want to extend the `AddToCartPlugin` instead of overriding it, you need to call the original method in your new method like this:

```js
import AddToCartPlugin from 'src/plugin/add-to-cart/add-to-cart.plugin';

export default class CustomAddToCartPlugin extends AddToCartPlugin {
    _openOffCanvasCart() {
      // Call the original method  
      super._openOffCanvasCart();
      
      // Then do your own stuff
      console.log('Item added to cart without opening offcanvas');
    }

}
```

</Callout>

#### Register the Override in the `main.js` File

As mentioned, the `main.js` file is the entry point. This means the override happens there:

```js
import ExamplePlugin from './example-plugin/example-plugin.plugin';
import CustomAddToCartPlugin from './custom-add-to-cart/custom-add-to-cart.plugin';

const PluginManager = window.PluginManager;

PluginManager.register('ExamplePlugin', ExamplePlugin, '[data-example-plugin]');
PluginManager.override('AddToCart', CustomAddToCartPlugin, '[data-add-to-cart]'); // <-- Override the AddToCartPlugin here
```

- The `CustomAddToCartPlugin` is imported from the `custom-add-to-cart` folder.
- We override the `AddToCart` plugin with the `CustomAddToCartPlugin` with this code line `PluginManager.override('AddToCart', CustomAddToCartPlugin, '[data-add-to-cart]');`.

This means in detail: The `AddToCart` Plugin is registered in Shopware-storefront core like this:

```js
import AddToCart from 'src/plugin/add-to-cart/add-to-cart.plugin';

const PluginManager = window.PluginManager;

PluginManager.register('AddToCart', AddToCart, '[data-add-to-cart]');
```

And you call it the same way, but with the `override` method, and you pass the `CustomAddToCartPlugin` as the second argument.

If you are following this via the GitHub Repo please checkout the tag: `LU-02-custom-js-override`.

Now everything should work as expected. The offcanvas cart should not open anymore when you add a product to the cart.

#### Before

![Offcanvas cart before](assets/offcanvasCartBefore.jpg)

#### After

![Offcanvas cart after](assets/offcanvasCartAfter.jpg)

Congratulations, you have successfully overridden the `AddToCartPlugin`!

If you want to learn more about JavaScript and Shopware storefront JavaScript plugins, please check out the following resources:

- <https://developer.mozilla.org/de/docs/Web/JavaScript>

- <https://www.typescriptlang.org/>

- <https://developer.shopware.com/docs/guides/plugins/plugins/storefront/add-custom-javascript.html#writing-a-javascript-plugin>

## Special Case: Overriding Async Storefront JavaScript Plugins

Some storefront plugins in Shopware are registered **asynchronously**. This means, if you override such a plugin, your override must also be registered asynchronously. Otherwise, the override will not be applied.

Async plugins are typically used for functionality needed only on certain pages. Typical examples include:

- Product detail page features
- Checkout-specific functionality
- Start page features
- CMS landing pages
- Other page-specific features

Loading these plugins only when required helps keep the **initial storefront JavaScript payload** smaller, which improves loading performance.

Therefore, whenever you override a plugin, it is good practice to check whether the original plugin is registered synchronously or asynchronously and register your override in the same way.

### Example

Imagine the `AddToCartPlugin` is registered asynchronously. Your override should then look like this:

```js
const PluginManager = window.PluginManager;

PluginManager.override(
  'AddToCart',
  () => import('./custom-add-to-cart/custom-add-to-cart.plugin'),
  '[data-add-to-cart]'
);
```

**What happens here?**

Instead of importing your custom plugin at the top of the file and passing it to the `override` method, you use a **dynamic import**:

```js
() => import('./custom-add-to-cart/custom-add-to-cart.plugin')
```

This tells Shopware to load the plugin only when it is necessary, instead of loading it together with the rest of the storefront JavaScript.

## Summary

In this learning unit, you learned the basics of **storefront JavaScript** in Shopware. Specifically, you now know how to:

- Create a new storefront JavaScript plugin with the CLI or GitHub example.
- Use the **`main.js`** entry file and the **`PluginManager`** to register and link plugins.
- Attach your plugin to an element via data attribute (e.g., `template data-example-plugin`).
- Build and watch the storefront with the provided Shopware scripts (**`build-storefront.sh`** and **`watch-storefront.sh`**).
- Extend or override existing storefront JavaScript plugins, such as the `AddToCartPlugin`.
- Understand the difference between synchronous and asynchronous storefront JavaScript plugins.

With this knowledge, you can start changing and extending the **behavior** of your shop in a structured and maintainable way.
