Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d3574e8
docs(administration): add entrypoint for sfc documentation
davidtraum Sep 8, 2026
e257c35
docs(administration): add a hands-on tutorial for SFC extensions
gweiermann Sep 10, 2026
2a13bca
docs(administration): lead every before/after tab with its template
gweiermann Sep 11, 2026
fbbd0a0
docs(administration): retake the tutorial screenshots on a clean shop
gweiermann Sep 11, 2026
e9c45ef
docs(administration): add the SFC API reference
gweiermann Sep 11, 2026
713c6f7
docs(administration): import the composables in the API reference
gweiermann Sep 11, 2026
07b46a6
docs(administration): nest the tutorial chapters under a parent page
gweiermann Sep 11, 2026
87fcd36
Merge the tutorial branch, and split the reference into one page per API
gweiermann Sep 11, 2026
acfe394
docs(administration): group the reference into macros, composables an…
gweiermann Sep 11, 2026
5dac8de
docs: do not show imports for the override composables
gweiermann Sep 11, 2026
c911de5
Merge the tutorial branch
gweiermann Sep 11, 2026
42d1885
docs(administration): the override composables are not imported either
gweiermann Sep 11, 2026
8fa33ef
docs(administration): document every Administration composable
gweiermann Sep 11, 2026
9b10458
docs(administration): document useCmsElementDeprecated and how to mov…
gweiermann Sep 11, 2026
ddf13e9
docs(administration): one page per composable
gweiermann Sep 11, 2026
9edefee
docs(administration): drop the Vue composables section from the index
gweiermann Sep 11, 2026
521d32d
docs(administration): add the SFC roadmap page
gweiermann Sep 11, 2026
33bd648
docs(administration): explain the SFC internals
gweiermann Sep 14, 2026
dbceeaf
docs(administration): add timeline to index page
davidtraum Sep 15, 2026
7136325
docs(administration): improve index page
davidtraum Sep 15, 2026
4429c8a
docs(administration): add link hint
davidtraum Sep 15, 2026
b814ce8
docs(administration): fix markdown
davidtraum Sep 15, 2026
db28bf7
Merge branch 'main' into docs/admin-vue-sfc-extensions
davidtraum Sep 15, 2026
e8591ae
docs(administration): fix table alignment
davidtraum Sep 15, 2026
074b2db
docs(administration): fix table alignments
davidtraum Sep 15, 2026
258b08c
docs: add some improvements, cross references, etc.
jleifeld Sep 16, 2026
500c707
docs: add discussion link
davidtraum Oct 2, 2026
943a9d7
docs: update composable imports
davidtraum Oct 5, 2026
2319277
docs: update v-if usage on sw-block-extends
davidtraum Oct 5, 2026
100cae5
docs: fix code example
davidtraum Oct 5, 2026
9d42471
docs: explain cache clear for new admin snippets
gweiermann Oct 5, 2026
a821620
docs: use console commands for extension tooling
gweiermann Oct 5, 2026
624b5bf
docs: update product menu path
gweiermann Oct 5, 2026
a1897dd
docs: describe what actually changes at the chapter 4 checkpoint
gweiermann Oct 5, 2026
c242a39
docs: address review findings in the SFC extension documentation
jleifeld Oct 6, 2026
f133eea
docs: fix spellcheck in the composables reference
jleifeld Oct 6, 2026
e73c698
docs: apply review feedback on the SFC tutorial
gweiermann Oct 7, 2026
2fab96c
docs: show the by-name registration before the route exception
gweiermann Oct 7, 2026
6a96a00
docs: correct SFC docs against trunk and fill gaps found in review
gweiermann Oct 7, 2026
3464028
docs: date the SFC system to 6.7.16.0 and separate the BC promise fro…
gweiermann Oct 7, 2026
53092d2
docs: regenerate the SFC internals from the current transform
gweiermann Oct 7, 2026
f827893
docs: add demo data to the SFC tutorial setup and trim chapter 2
gweiermann Oct 7, 2026
90c398d
docs: show the template values before the template in chapter 3
gweiermann Oct 7, 2026
c165480
Merge branch 'main' into docs/admin-vue-sfc-extensions
gweiermann Oct 7, 2026
0c9892c
docs: update faq for vue-native migration
davidtraum Oct 7, 2026
2464b53
Merge branch 'main' into docs/admin-vue-sfc-extensions
sushmangupta Oct 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ Codestyle
Cognito
CommercialB
CommercialBundle
CommonJS
ComponentFactory
Composables
ConfigJson
Expand Down Expand Up @@ -1353,12 +1354,14 @@ cmss
codebase
codeblock
codeblocks
codemod
codemods
codereview
colorpicker
compatability
componentSectionRenderer
composable
composables
config
configComponent
configs
Expand Down Expand Up @@ -1450,6 +1453,7 @@ dereference
dereferenced
describeFeatures
destructure
destructured
destructuring
dev
devenv
Expand Down Expand Up @@ -1521,6 +1525,7 @@ externalReference
failover
fallback
fallbacks
fallthrough
fastly
favicon
fetchable
Expand Down Expand Up @@ -1644,10 +1649,12 @@ init
initialisms
initializer
initializers
inlines
installable
instantiation
integrations
interceptable
interop
intl
invalidations
io
Expand Down Expand Up @@ -1821,6 +1828,7 @@ otel
otlp
overridable
overrideComponentSetup
overrideable
oversales
paas
packagist
Expand Down Expand Up @@ -2042,6 +2050,7 @@ snackbar
snackbars
snakeCase
sortings
sourcemap
sourcemaps
sql
src
Expand Down Expand Up @@ -2087,6 +2096,8 @@ substring
supervisord
svg
sw
swDefineOverride
swDefinePublic
swSelect
sw_extends
swoole
Expand Down Expand Up @@ -2159,8 +2170,11 @@ unhandled
uninstallation
uniqBy
unminified
unmount
unmounting
unprefixed
unregister
unregisters
unrequested
unsecure
unserialize
Expand All @@ -2176,7 +2190,27 @@ uptime
uri
url
urls
useCmsElement
useCmsState
useInlineSnippet
useListing
useMediaGridListener
useMediaSidebarModal
useNotification
useNotificationTranslation
usePlaceholder
usePosition
useRuleBetweenOperator
useRuleContainer
useSalutation
useSwContext
useSwPreviousState
useSwProps
useTranslateWithFallback
useUserSettings
useValidation
useValidityRange
useVideoCover
userAware
userRecovery
userland
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/administration-sfc-tutorial-component.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/administration-sfc-tutorial-extended.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/administration-sfc-tutorial-margin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions guides/plugins/plugins/administration/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ This section follows a practical development workflow. Start with registering a

For stable cross-version extension points, use the [Meteor Admin SDK](../../apps/administration/meteor-admin-sdk.md). The SDK can be used by both apps and plugins.

Components can also be written as native Vue [Single File Components](single-file-components/index.md). This is the experimental alternative, available since Shopware 6.7.16.0, to the Options API and TwigJS templates described in this section, which stay the stable way today. The fastest way in is the [SFC tutorial](single-file-components/tutorial/index.md).

## Developer workflow

When extending the Administration inside a plugin, follow this sequence:
Expand All @@ -35,6 +37,7 @@ When extending the Administration inside a plugin, follow this sequence:
6. [Inject services](services-utilities/injecting-services.md) and [extend services](services-utilities/extending-services.md)
7. [Customize templates](templates-styling/writing-templates.md) and [add custom styles](templates-styling/add-custom-styles.md)
8. Manage state using [Vuex](data-handling-processing/using-vuex-state.md) or [Pinia](../../../upgrades-migrations/administration/pinia.md)
9. Optional: try the experimental [Single File Component extension system](single-file-components/index.md) by following its [tutorial](single-file-components/tutorial/index.md)

Advanced topics such as [mixins and directives](mixins-directives/using-mixins.md) or [extending webpack](advanced-configuration/extending-webpack.md) are covered separately.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ nav:

# Using Mixins

::: info
Mixins are the stable way to share component logic today. A Single File Component cannot use them, so the experimental Single File Component system is adding composables for the commonly used mixins. See [Composables replacing mixins](../single-file-components/roadmap.md#composables-replacing-mixins) for the current state of that list.
:::

## Overview

This guide covers how to use an existing Administration mixin in a plugin. Generally, mixins behave the same as they do in Vue normally, differing only in the registration and the way mixins are included in a component.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ nav:

# Add Custom Components

::: info
The Options API registration shown on this page is the stable way to build a component today. Since Shopware 6.7.16.0, a component can also be written as a native Vue [Single File Component](../single-file-components/index.md), the experimental alternative. See the [SFC tutorial](../single-file-components/tutorial/index.md) if you want to try it.
:::

## Overview

Since the Shopware 6 Administration is using [VueJS](https://vuejs.org/) as its framework, it also supports creating custom components. This guide will teach you how to register your own custom component with your plugin.
Expand Down Expand Up @@ -156,5 +160,6 @@ You've now added a custom component, including a little template. However, there
* [More about templates](../templates-styling/writing-templates.md)
* [Add some styling to your component](../templates-styling/add-custom-styles.md)
* [Use shortcuts for your component](../advanced-configuration/add-shortcuts.md)
* [Build the same component as an experimental Single File Component](../single-file-components/tutorial/build-your-own-component.md)

Furthermore, what about [customizing other components](customizing-components.md), instead of creating new ones?
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ nav:

# Customizing Components

::: info
`Component.override()` with TwigJS blocks, as shown on this page, is the stable way to customize a component today. Its counterpart in the experimental Single File Component system, available since Shopware 6.7.16.0, is an `.override.vue` file using `<sw-block extends>`. See [Chapter 2: Your first override](../single-file-components/tutorial/your-first-override.md).
:::

## Overview

The Shopware 6 Administration allows you to override and extend components to change its content and its behavior.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
nav:
title: Block components
position: 30

---

# Block components

<!--@include: ../../../../../../../snippets/guide/administration_sfc_experimental.md-->

Two globally registered components carry the native block system. You write the tags without importing anything.

<PageRef page="sw-block" title="sw-block" sub="Declare an extension point, or contribute to one" />
<PageRef page="sw-block-parent" title="sw-block-parent" sub="Render what the extension point held before you" />

## The model

A component **declares** an extension point by wrapping markup in `<sw-block name="…">`. Its children are the default content, and with nothing registered against the name it renders as though the wrapper were not there.

An override **contributes** to that point with `<sw-block extends="…">`. That tag renders nothing where it stands: it registers its content, and the matching `<sw-block name>` renders it wherever that happens to be.

```html
<!-- swag-greeting-card.vue -->
<sw-block name="swag_greeting_card_body">
<p>Default content</p>
</sw-block>

<!-- swag-greeting-card.override.vue -->
<sw-block extends="swag_greeting_card_body">
<sw-block-parent />
<p>Mine, underneath</p>
</sw-block>
```

## Names

A block name is a plain string and nothing validates it, so a typo matches nothing and fails silently. Names must be unique per component.

The convention is an owner prefix, then the path through the component, in `snake_case`:

```text
sw_product_detail_base_price_form
swag_greeting_card_body
```

Core uses `sw_`; a plugin uses its own prefix. A block name you find in core is covered by the backwards-compatibility promise: it stays until the next major version, and if one is removed in a major, the changelog names it. When core converts a component to a Single File Component, its block names stay the same.

## Chains

Several overrides may target one block. They stack in registration order, and each one's `<sw-block-parent />` renders the previous one's output rather than the original default. Leaving `<sw-block-parent />` out replaces everything below it, which is how one plugin removes another plugin's contribution.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
nav:
title: sw-block-parent
position: 70

---

# `sw-block-parent`

<!--@include: ../../../../../../../snippets/guide/administration_sfc_experimental.md-->

```html
<sw-block-parent />
```

Takes no props. Renders whatever the extension point held before this override: the default content, or the previous override in the chain. Globally registered, so you write the tag without importing anything.

Leave it out and the original markup is replaced.

## Position decides yours

```html
<!-- append -->
<sw-block extends="swag_greeting_card_body">
<sw-block-parent />
<p>I go after</p>
</sw-block>

<!-- prepend -->
<sw-block extends="swag_greeting_card_body">
<p>I go before</p>
<sw-block-parent />
</sw-block>

<!-- replace -->
<sw-block extends="swag_greeting_card_body">
<p>The original content is gone</p>
</sw-block>
```

## Render it once, unconditionally

It claims its position in the chain when it is created, so a `v-if` on it, or a `v-for` around it, corrupts that chain. One `<sw-block-parent />` per extending block, always rendered.
Comment thread
davidtraum marked this conversation as resolved.
Resolved

## Chains

When several overrides target one block they stack, and each one's `<sw-block-parent />` renders the previous one's output rather than the original default. That is what keeps other plugins on the page when your own change is additive.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
nav:
title: sw-block
position: 60

---

# `sw-block`

<!--@include: ../../../../../../../snippets/guide/administration_sfc_experimental.md-->

The extension point. Globally registered, so you write the tag without importing anything. Which prop you pass decides what it does.

| Prop | Type | Meaning |
| --------- | -------- | ------------------------------------------------------------------------------------ |
| `name` | `string` | **Declares** an extension point. Its children are the default content |
| `extends` | `string` | **Contributes** to the extension point of that name. Renders nothing where it stands |

Write `name` (base components only) or `extends` (overrides only) as a static attribute and nothing else. The component has other props - your editor may offer them - and they are internal. The build rejects any other attribute or directive on the tag, including `class`, `v-if`, a bound `:extends`, `data`, `v-bind` and an authored `#default`.

## Declaring an extension point

```html
<sw-block name="swag_greeting_card_body">
<p>Default content</p>
</sw-block>
```

With nothing registered against the name, this renders as though the wrapper were not there.

## Contributing to one

```html
<sw-block extends="swag_greeting_card_body">
<sw-block-parent />
<p>Mine, underneath</p>
</sw-block>
```

The target block is replaced by what goes inside. To keep what was there, render [`sw-block-parent`](sw-block-parent).

An `<sw-block extends>` belongs at the root of an override's template and cannot be nested inside another element. Where it sits does not affect where its content renders: it registers the content, and the matching `<sw-block name>` renders it.

## Names

Block names are strings and nothing validates them, so a typo silently matches nothing. They must be unique per component. The convention is an owner prefix and then the path through the component, in `snake_case`: core uses `sw_`, a plugin uses its own.

```text
sw_product_detail_base_price_form
swag_greeting_card_body
```

## Bindings in block content

Your override's bindings are available inside its `<sw-block extends>` content and read like any other Vue template binding. Mutating one from the template - `@click="counter++"` - is not supported; wrap the mutation in a function and call that instead.

## Order, when several extensions meet

Native `<sw-block extends>` contributions render in registration order, and all of them render after a TwigJS override of the same block. A legacy override is therefore always the parent of a native one, whichever order the plugins load in.

<PageRef page="../../internals" title="Internals" sub="How the chain is assembled, and why the order is what it is" />
Loading