Skip to content

shopware/frontends - cms-base

shopware/frontends - cms-base ​

Nuxt layer that provides an implementation of all CMS components in Shopware based on utility-classes.

It is useful for projects that want to use the CMS components while keeping CMS functionality separate from the styling system and design tokens.

Features ​

Setup ​

Install npm package:

sh
# ✨ Auto-detect
npx nypm install -D @shopware/cms-base-layer

# npm
npm install -D @shopware/cms-base-layer

# yarn
yarn add -D @shopware/cms-base-layer

# pnpm
pnpm add -D @shopware/cms-base-layer

# bun
bun install -D @shopware/cms-base-layer

# deno
deno install --dev npm:@shopware/cms-base-layer

If you also want the shared Shopware Frontends UnoCSS setup, install @shopware/unocss-design-tokens-layer in your app and extend it alongside @shopware/cms-base-layer.

Then, register the Nuxt layer in nuxt.config.ts file:

ts
// https://v3.nuxtjs.org/api/configuration/nuxt.config
const isStackBlitz = process.env.SHOPWARE_STACKBLITZ === "true";

export default defineNuxtConfig({
  extends: ["@shopware/composables/nuxt-layer", "@shopware/cms-base-layer"],
  ...(isStackBlitz ? { devtools: { enabled: false } } : {}),
  shopware: {
    endpoint: "https://demo-frontends.shopware.store/store-api/",
    accessToken: "SWSCBHFSNTVMAWNZDNFKSHLAYW",
  },
  modules: ["@shopware/nuxt-module"],
  /**
   * Commented because of the StackBlitz error
   * Issue: https://github.com/shopware/frontends/issues/88
   */
  typescript: {
    // typeCheck: true,
    strict: true,
  },
  telemetry: false,
});

Basic usage ​

Since all CMS components are registered in your Nuxt application, you can now start using them in your template (no imports needed):

js
/* Vue component */

// response object can be a Product|Category|Landing Page response from Shopware 6 store-api containing a layout (cmsPage object) built using  Shopping Experiences
<template>
    <CmsPage v-if="response.cmsPage" :content="response.cmsPage"/>
</template>

@shopware/cms-base-layer no longer owns the default UnoCSS theme. If you want the shared Shopware Frontends design tokens and UnoCSS defaults, extend @shopware/unocss-design-tokens-layer as shown above.

See a short guide on how to use cms-base-layer in your Nuxt project.

Styling and Design Tokens ​

The components use utility classes, but the shared UnoCSS configuration, design tokens, and runtime handling for dynamic CMS classes are now provided by @shopware/unocss-design-tokens-layer.

This means you have two options:

  • extend @shopware/unocss-design-tokens-layer to use the shared Shopware Frontends token palette and UnoCSS defaults
  • keep only @shopware/cms-base-layer and provide your own UnoCSS or Tailwind setup

When you use the design-tokens layer, you can customize the generated config in your project's uno.config.ts:

ts
// nuxt.config.ts
export default defineNuxtConfig({
  // ...
  unocss: {
    nuxtLayers: true, // enable Nuxt layers for UnoCSS
  },
});
ts
import { mergeConfigs } from "@unocss/core";
import baseConfig from "./.nuxt/uno.config.mjs";

export default mergeConfigs([
  baseConfig,
  {
    theme: {
      colors: {
        "brand-primary": "#ff3e00",
        "brand-secondary": "#1c1c1c",
      },
    },
  },
]);

See the UnoCSS reference for more information on how to configure UnoCSS in Nuxt when work with layers.

🖼️ Image Optimization ​

This layer includes Nuxt Image configuration optimized for Shopware 6 instances, with a custom provider that maps Nuxt Image modifiers to Shopware's query parameters (width, height, quality, format, fit).

Note for Cloud (SaaS) Users: Image optimization and all modifiers used in the Nuxt Image module are handled automatically by Shopware Cloud infrastructure powered by Fastly CDN. No additional configuration or plugins are required - simply use <NuxtImg> and all transformations (format conversion, quality adjustment, responsive sizing) work out of the box through Fastly's Image Optimizer.

Features ​

  • ✅ Automatic WebP/AVIF format conversion
  • ✅ Responsive image sizing based on viewport
  • ✅ Lazy loading support
  • ✅ Quality optimization
  • ✅ Multiple image presets for common use cases
  • ✅ Works with Shopware Cloud (SaaS) and self-hosted instances

Configuration ​

The layer comes pre-configured with optimized settings. No additional setup is required! The configuration includes:

Available Presets:

  • productCard - Product listing images (WebP, quality 90, cover fit)
  • productDetail - Product detail page images (WebP, quality 90, contain fit)
  • thumbnail - Small thumbnails (150x150, WebP, quality 90)
  • hero - Hero banners (WebP, quality 95, cover fit)

Responsive Breakpoints:

  • xs: 320px, sm: 640px, md: 768px, lg: 1024px, xl: 1280px, xxl: 1536px

Usage in Components ​

Replace standard <img> tags with <NuxtImg> to enable automatic optimization:

vue
<!-- Using presets -->
<NuxtImg
  src="https://cdn.shopware.store/media/path/to/image.jpg"
  preset="productCard"
  :width="400"
  alt="Product"
  loading="lazy"
/>

<!-- Custom modifiers -->
<NuxtImg
  src="https://cdn.shopware.store/media/path/to/image.jpg"
  :width="800"
  :height="600"
  format="webp"
  :quality="85"
  fit="cover"
  alt="Custom image"
/>

<!-- Using with dynamic Shopware media URLs -->
<NuxtImg
  :src="product.cover.media.url"
  preset="productDetail"
  :width="800"
  :alt="getTranslatedProperty(product.cover.media, 'alt')"
/>

The media alt text is a translatable field, so read it through getTranslatedProperty rather than media.alt — the latter always holds the system language value, no matter which language the current request asks for. The helper is not auto-imported, so add it to the component's script block:

ts
import { getTranslatedProperty } from "@shopware/helpers";

Supported Modifiers ​

Shopware supports the following URL parameters for image transformation:

ModifierDescriptionExampleSupport
widthImage width in pixels400✅ Always supported
heightImage height in pixels600✅ Always supported
qualityImage quality (0-100)85⚠️ Cloud/Plugin required*
formatOutput formatwebp, avif, jpg, png⚠️ Cloud/Plugin required*
fitResize behaviorcover, contain, fill⚠️ Cloud/Plugin required*

*Advanced transformations (quality, format, fit) are available in:

How It Works ​

This layer includes a custom Shopware provider for Nuxt Image that maps modifiers to Shopware's query parameters:

  • width modifier → ?width=400
  • height modifier → ?height=300
  • quality modifier → ?quality=85
  • format modifier → ?format=webp
  • fit modifier → ?fit=cover

When you use <NuxtImg>, the custom provider automatically converts your component props into the correct URL format for Shopware. The images are then processed on-the-fly by Shopware Cloud (SaaS) infrastructure or your configured thumbnail processor.

🔍 Understanding Image Processing in Shopware ​

Built-in Thumbnail Generation: Shopware has native thumbnail generation (using GD2 or ImageMagick) that creates predefined sizes (400x400, 800x800, 1920x1920) during image upload. These thumbnails are generated once and stored on your server.

Dynamic On-the-Fly Transformations: For dynamic image transformations via query parameters (like ?width=800&format=webp), you need remote thumbnail generation configured:

  • Shopware Cloud (SaaS): ✅ Fully supported out-of-the-box via Fastly CDN - all query parameters work automatically
  • Self-hosted: ⚠️ Requires additional setup:

Without remote thumbnail generation configured, query parameters will be ignored and only the predefined static thumbnails will be served.

💡 Recommendation: If you're self-hosting Shopware and want to use dynamic image transformations with Nuxt Image modifiers, install the FroshPlatformThumbnailProcessor plugin first to enable on-the-fly processing.

Customizing Configuration ​

You can extend or override the default settings in your project's nuxt.config.ts:

ts
export default defineNuxtConfig({
  extends: ["@shopware/cms-base-layer"],

  image: {
    // Change default quality
    quality: 85,

    // Add/change formats
    formats: ["avif", "webp", "jpg"],

    // Override or add presets
    presets: {
      // Override existing preset
      productCard: {
        modifiers: {
          format: "avif",
          quality: 80,
          fit: "cover",
        },
      },
      // Add custom preset
      categoryBanner: {
        modifiers: {
          format: "webp",
          quality: 90,
          width: 1200,
          height: 400,
          fit: "cover",
        },
      },
    },
  },
});

🖼️ Image Placeholder ​

This layer provides a useImagePlaceholder composable that generates an SVG placeholder for images during loading. The placeholder features a centered icon with a subtle background.

Customizing Placeholder Color ​

You can customize the placeholder color globally in your project's app.config.ts:

ts
export default defineAppConfig({
  imagePlaceholder: {
    color: "#your-color-here", // Default: #543B95
  },
});

Or use a custom color for specific instances:

vue
<script setup>
const customPlaceholder = useImagePlaceholder("#FF0000");
</script>

<template>
  <NuxtImg :placeholder="customPlaceholder" src="..." />
</template>

🖼️ Background Image Optimization ​

CMS sections and blocks can have background images set via the Shopware admin. This layer automatically optimizes those background image URLs by appending format and quality query parameters — bringing the same optimization applied to <NuxtImg> components to CSS background images.

Both CmsPage (for section backgrounds) and CmsGenericBlock (for block backgrounds) read the configuration from app.config.ts and pass it to the getBackgroundImageUrl helper from @shopware/helpers.

Configuration ​

Default values are set in app.config.ts and can be overridden in your project:

ts
export default defineAppConfig({
  backgroundImage: {
    format: "webp", // Default: "webp" — output format ("webp" | "avif" | "jpg" | "png")
    quality: 90, // Default: 90 — image quality (0-100)
  },
});

Setting format or quality to undefined (or omitting the key) will skip that parameter in the generated URL.

How It Works ​

When a CMS section or block has a backgroundMedia set, the components call getBackgroundImageUrl() which:

  1. Extracts the raw image URL from the CSS url() value
  2. Appends width or height based on the image's original dimensions (capped at 1920px)
  3. Adds fit=crop,smart for intelligent cropping
  4. Appends format and quality from app.config.ts if provided

Example generated URL:

url("https://cdn.shopware.store/.../image.jpg?width=1000&fit=crop,smart&format=webp&quality=85")

Note: Like other dynamic image transformations, background image optimization requires remote thumbnail generation support. See the Image Optimization section above for Shopware Cloud vs. self-hosted requirements.

LCP Image Preload ​

This layer includes a useLcpImagePreload composable that preloads the first image found in CMS page content when enabled via lcpImagePreload: true in your app.config.ts (disabled by default). This targets the Largest Contentful Paint (LCP) element, which is often a hero background image or the first visible image element.

How it works ​

The composable scans CMS sections in document order, checking:

  1. Section background images (section.backgroundMedia)
  2. Block background images (block.backgroundMedia)
  3. Image element media (slot.data.media)

The first image found is injected as a <link rel="preload" as="image" fetchpriority="high"> in the <head> during SSR. This allows the browser to start fetching the LCP image immediately, before parsing CSS or executing JavaScript. The fetchpriority="high" attribute ensures the preload is prioritized — this is especially useful for background images which don't natively support fetchpriority.

Usage ​

The composable is already called in CmsPage.vue. If you override CmsPage, you can use it in your custom component. It is auto-imported once your app extends this layer, so it needs no import statement:

vue
<script setup>
const props = defineProps<{ content: Schemas["CmsPage"] }>();

useLcpImagePreload(props.content?.sections || []);
</script>

The preload URL includes the optimized format and quality parameters from app.config.ts for both background images and element images.

Responsive CMS Images ​

Images are optimized to prevent the browser from downloading images larger than their displayed dimensions — a common Lighthouse performance issue.

Product Card Images (SwProductCardImage) ​

The productCard preset only defines URL modifiers (format/quality/fit). width/height and loading stay on the component: in @nuxt/image 2.1.0 a preset carries width/height only as modifiers, which shape the URL rather than the rendered attributes, and loading is not a preset field at all. densities is kept alongside them for consistency, though a preset would propagate it:

ts
// nuxt.config.ts
productCard: {
  modifiers: { format: "webp", quality: 90, fit: "cover" },
}
vue
<NuxtImg
  preset="productCard"
  :src="coverSrcPath"
  width="400"
  height="400"
  densities="1x"
  loading="lazy"
/>
  • Fixed width/height (400px) — avoid hydration mismatches caused by dynamic DOM measurement
  • densities="1x" — prevents duplicate retina requests
  • loading="lazy" — defers off-viewport images

⚠️ Avoid adding decoding or sizes props on the component — they trigger Vue hydration attribute mismatches with NuxtImg, which cause duplicate image requests.

CMS Images (CmsElementImage) ​

CMS image elements use useElementSize() to measure the rendered container and pass the size to <NuxtImg> via width/height props:

  • During SSR, no image is fetched (size is undefined)
  • After hydration, the container is measured and a single correctly-sized image is requested
  • The size is multiplied by 2 (for retina) and rounded up to the nearest 100px

Slider Components ​

Slider components (CmsElementProductSlider, CmsElementCrossSelling) inject the slot count via cms-block-slot-count to scale their SSR breakpoints — ensuring media queries account for the container being a fraction of the viewport.

LCP Image Preloading ​

useLcpImagePreload scans CMS sections for the first image and injects <link rel="preload" as="image" fetchpriority="high"> during SSR.

🔄 UnoCSS Runtime ​

When you extend @shopware/unocss-design-tokens-layer, you also get a client-side UnoCSS runtime plugin that resolves utility classes dynamically at runtime using a DOM MutationObserver. This is useful when CMS content from Shopware contains utility classes that aren't known at build time (for example inline utility classes configured in the admin panel).

The runtime is enabled by default. To disable it, set unocssRuntime to false in your project's app.config.ts:

ts
export default defineAppConfig({
  unocssRuntime: false,
});

When to disable: If you don't use dynamic CMS utility classes, or if you experience performance issues caused by the MutationObserver in pages with frequent DOM mutations.

📘 Available components ​

The list of available blocks and elements is here.

🔄 Overwriting components ​

The procedure is:

  • find a component in component's list, using a Vue devtools or browsing the github repository
  • take its name
  • create a file with the same name and place it under a components directory that your nuxt.config.ts registers with global: true — CMS components are looked up with resolveComponent, so an override outside a global path is never found and this layer's version keeps rendering with no error. In the starter template that directory is app/components/cms/; because it is registered with pathPrefix: false, the name comes from the filename alone and subdirectory depth under it does not matter.

✅ Thanks to this, nuxt will take the component registered in your app instead of the one registered by this nuxt layer.

App blocks (app-renderer) ​

Every block an app registers through the Meteor Admin SDK (cms.registerCmsBlock) reaches the Store API with the type app-renderer, so they all render through CmsBlockAppRenderer. By default it places the block's slots in the CSS grid the app declared, like the Storefront's fallback, in the order the app declared them.

To give one app block its own markup, add a global component named after the block, CmsBlockAppRenderer followed by the PascalCase appBlockName — for a block registered as swag-two-columns, that is CmsBlockAppRendererSwagTwoColumns.vue. It receives the block as its content prop, and every other app block keeps the fallback:

vue
<script setup lang="ts">
import type { CmsBlockAppRenderer } from "@shopware/composables";

const props = defineProps<{ content: CmsBlockAppRenderer }>();

const { getSlotContent } = useCmsBlock(() => props.content);

const text = computed(() => getSlotContent("text-0"));
const image = computed(() => getSlotContent("image-1"));
</script>

<template>
  <div class="grid gap-6 md:grid-cols-2">
    <CmsGenericElement :content="text" />
    <CmsGenericElement :content="image" />
  </div>
</template>

The slots are named {element}-{index} in the order the app declared them, so look them up by name rather than by position: the Store API sorts them by name, so image-1 comes before text-0 and text-10 before text-2. The fallback restores the declared order from the index, as the Administration preview shows it. The Storefront's fallback keeps the Store API order, so a block that mixes element types can place its slots differently there.

The lookup of these components lives in CmsBlockAppRenderer itself. If you override CmsBlockAppRenderer, for example to change the fallback markup, your override replaces that lookup too, and your CmsBlockAppRenderer{AppBlockName} components are no longer used unless it renders them. A component whose name does not match the appBlockName renders the fallback without a warning, as a misnamed override of any other CMS component does.

Internal components ​

❗Internal components are not a part of public API. Once overwritten you need to track the changes on your own.

There is also a possibility to override the internal components, shared between public blocks and elements, the ones starting with Sw prefix, like SwSlider.vue or SwProductCard.vue.

An example: some components use SwSharedPrice.vue to show prices with corresponding currency for products in many places like product card, product details page and so on. In order to change the way how the price is displayed consistently - create a one component with a name SwSharedPrice.vue and that's it. The new component will be used everywhere where is "imported" (autoimported actually).

Some components use RouterLink component internally, available in Vue Router. In order to parse CMS components correctly and avoid missing component warning, it's highly recommended to have Vue Router installed or Nuxt router enabled in your application.

TypeScript support ​

All components are fully typed with TypeScript.

No additional packages needed to be installed.

Changelog ​

Full changelog for stable version is available here

Latest changes: 4.0.0 ​

Major Changes ​

  • #2609 2dc86da Thanks @mkucmus! - Make the package a plain Nuxt layer.

    Breaking: the package now declares an exports map, so only the layer entry point is importable. Deep imports such as @shopware/cms-base-layer/app/components/SwProductCard.vue no longer resolve. Use the auto-registered global components instead, which is what extending the layer gives you.

    Breaking: the leftover Nuxt module is gone, so index.cjs and the dist build are no longer published. The module registered a component folder that moved to app/ a while ago, so it could not work any more. Consume this package with extends, which resolves nuxt.config.ts:

    ts
    export default defineNuxtConfig({
      extends: ["@shopware/cms-base-layer"],
    });

    Other changes:

    • Dropped the build and dev scripts and the unbuild dev dependency. There is nothing left to bundle.
    • Fixed files. It listed helpers and app.config.ts, which do not exist at the package root, and shipped the dead dist and index.cjs.
    • Deleted components.d.ts. It typed two components at paths that moved to app/components/public/cms/, and no tsconfig referenced the file.
    • Removed two vitest aliases that pointed at files which do not exist.
    • Removed the check-colors script. It read uno.config.ts from this package, which moved to @shopware/unocss-design-tokens-layer, so it always found zero colors. It also relied on tsx without declaring it.

Minor Changes ​

  • #2574 2ddf156 Thanks @mkucmus! - SwProductListingFilters and SwProductListingFiltersHorizontal render a new SwFilterCategories checkbox filter when the listing response contains the category aggregations from getCategoryFilterAggregations(). The selection is kept in the categories URL param and applied as a criteria post-filter. Both are search listings only (listing-type="productSearchListing"); on any other listing the category filter is not rendered, because the selection would neither reach the URL nor the criteria. Listings without these aggregations are unaffected.

Patch Changes ​

  • #2645 7a7ce3e Thanks @mkucmus! - Ship component-dirs.json in the published package. nuxt.config.ts imports it at load time, but it was missing from files, so the layer failed to load when installed from the registry.

  • #2660 8913956 Thanks @mdanilowicz! - Read translatable entity fields through their translated object instead of the untranslated entity root, so they follow the language of the current request instead of rendering the system language. Affected components: SwContactForm and SwNewsletterForm (salutation displayName), SwStockInfo (delivery time name), SwVariantConfigurator (property group name — the option values below it already used translated), CmsElementBuyBox (unit name), CmsElementCrossSelling (cross selling name), CmsElementProductDescriptionReviews (category name), SwProductCardImage and CmsElementImageGallery (media alt).

    All of them now go through getTranslatedProperty() from @shopware/helpers, which falls back to the root property when translated is missing — so the rendered value only ever changes on storefronts whose language differs from the system language.

  • #2606 1c9a604 Thanks @mkucmus! - Stop leaking internal types into the layer's public type surface.

    • index.d.ts now only augments the app config. It no longer re-exports @shopware/composables and ./.nuxt/imports.
    • The #imports shim moved to a private types/imports.d.ts, which is not published.
    • app.config exports a plain object with satisfies AppConfigInput instead of calling defineAppConfig. No runtime change.

    This fixes Cannot find name 'ref' and similar errors in the shared and node contexts when a project uses the Nuxt 4 project-references tsconfig.json.

  • #2601 e64d2f9 Thanks @mdanilowicz! - Typography for CMS-authored HTML is now scoped to a cms-element-text class and ships from the layer as app/assets/css/rich-text.css, with overflow guards for long strings, media, pre and tables. Headings and lists in your own markup that had no explicit size or list-* class were relying on the removed global rules and will change.

  • #2663 7020545 Thanks @mkucmus! - A linked CMS image always has an accessible name now. CmsElementImage names the link with the element's ariaLabel, then the media title, then a generic fallback translatable through cms.image.linkWithoutLabel. A decorative image skips the media title.

  • Updated dependencies [2ddf156, 204c8f4, 7020545, 183c183, 458494e, 183c183, 183c183, 8913956, 458494e]:

    • @shopware/helpers@1.8.0
    • @shopware/composables@1.13.0
    • @shopware/api-client@1.6.0

Available components ​

CmsBlockSpatialViewer ​

source code


CmsGenericBlock ​

source code

Renders a Block type structure.

Resolves the correct CMS block component dynamically and applies layout configuration (CSS classes, background color, background image). When a block has a backgroundMedia set, the component automatically optimizes the background image URL using the getBackgroundImageUrl helper from @shopware/helpers, appending format and quality parameters from the backgroundImage app config.

Background Image Optimization ​

Background image settings are read from app.config.ts:

ts
export default defineAppConfig({
  backgroundImage: {
    format: "webp",
    quality: 85,
  },
});

Example usage ​

vue
<script setup lang="ts">
import type { CmsSectionDefault } from "@shopware/composables";
import { getCmsLayoutConfiguration } from "@shopware/helpers";

const props = defineProps<{
  content: CmsSectionDefault;
}>();

const { cssClasses, layoutStyles } = getCmsLayoutConfiguration(props.content);
</script>

<template>
  <div class="cms-section-default" :class="cssClasses" :styles="layoutStyles">
    <CmsGenericBlock
      v-for="cmsBlock in content.blocks"
      class="overflow-auto"
      :key="cmsBlock.id"
      :content="cmsBlock"
    />
  </div>
</template>

CmsGenericElement ​

source code

Renders an Element type structure.

content is optional: getSlotContent() returns undefined for a slot the block does not carry, and this component renders nothing in that case.

Example usage:

vue
<script setup lang="ts">
import type { CmsBlockGalleryBuybox } from "@shopware/composables";
import { computed } from "vue";
import { useCmsBlock } from "#imports";

const props = defineProps<{
  content: CmsBlockGalleryBuybox;
}>();

// Pass a getter so the lookups follow a replaced block, and read them through
// computeds so each one re-runs when it does.
const { getSlotContent } = useCmsBlock(() => props.content);
const rightContent = computed(() => getSlotContent("right"));
const leftContent = computed(() => getSlotContent("left"));
</script>

<template>
  <div
    class="lg:container mx-auto flex flex-col lg:flex-row gap-10 justify-center"
  >
    <div class="overflow-hidden basis-4/6">
      <CmsGenericElement :content="leftContent" />
    </div>
    <div class="basis-2/6">
      <CmsGenericElement :content="rightContent" />
    </div>
  </div>
</template>

CmsNoComponent ​

source code


CmsPage ​

source code

An entrypoint to render the whole CMS object.

Resolves all CMS sections dynamically and applies their layout configuration. When a section has a backgroundMedia set, the component automatically optimizes the background image URL using the getBackgroundImageUrl helper from @shopware/helpers, appending format and quality parameters from the backgroundImage app config.

Background Image Optimization ​

Background image settings are read from app.config.ts:

ts
export default defineAppConfig({
  backgroundImage: {
    format: "webp", // output format
    quality: 85, // image quality (0-100)
  },
});

See the cms-base-layer README for full details.

Example usage ​

vue
<script setup lang="ts">
import { useLandingSearch } from "#imports";
import type { Schemas } from "#shopware";

const props = defineProps<{
  navigationId: string;
}>();

const { search } = useLandingSearch();

const { data: landingResponse } = await useAsyncData(
  "cmsLanding" + props.navigationId,
  async () => {
    const landingPage = await search(props.navigationId, {
      withCmsAssociations: true,
    });
    return landingPage;
  },
);

if (typeof landingResponse?.value !== null) {
  const landingPage = landingResponse as Ref<Schemas["LandingPage"]>;
  useCmsHead(landingPage, { mainShopTitle: "Shopware Frontends Demo Store" });
}
</script>

<template>
  <LayoutBreadcrumbs />
  <CmsPage v-if="landingResponse?.cmsPage" :content="landingResponse.cmsPage" />
</template>

FrontendAccountCustomerGroupRegistrationPage ​

source code


CmsBlockAppRenderer ​

source code


CmsBlockCategoryHeading ​

source code


CmsBlockCategoryNavigation ​

source code


CmsBlockCenterText ​

source code


CmsBlockCrossSelling ​

source code


CmsBlockCustomForm ​

source code


CmsBlockDefault ​

source code


CmsBlockForm ​

source code


CmsBlockGalleryBuybox ​

source code


CmsBlockHtml ​

source code


CmsBlockImage ​

source code


CmsBlockImageBubbleRow ​

source code


CmsBlockImageCover ​

source code


CmsBlockImageFourColumn ​

source code


CmsBlockImageGallery ​

source code


CmsBlockImageGalleryBig ​

source code


CmsBlockImageHighlightRow ​

source code


CmsBlockImageSimpleGrid ​

source code


CmsBlockImageSlider ​

source code


CmsBlockImageText ​

source code


CmsBlockImageTextBubble ​

source code


CmsBlockImageTextCover ​

source code


CmsBlockImageTextGallery ​

source code


CmsBlockImageTextRow ​

source code


CmsBlockImageThreeColumn ​

source code


CmsBlockImageThreeCover ​

source code


CmsBlockImageTwoColumn ​

source code


CmsBlockProductDescriptionReviews ​

source code


CmsBlockProductHeading ​

source code


CmsBlockProductListing ​

source code


CmsBlockProductSlider ​

source code


CmsBlockProductThreeColumn ​

source code


CmsBlockSidebarFilter ​

source code


CmsBlockText ​

source code


CmsBlockTextHero ​

source code


CmsBlockTextOnImage ​

source code


CmsBlockTextTeaser ​

source code


CmsBlockTextTeaserSection ​

source code


CmsBlockTextThreeColumn ​

source code


CmsBlockTextTwoColumn ​

source code


CmsBlockVideo ​

source code


CmsBlockVimeoVideo ​

source code


CmsBlockYoutubeVideo ​

source code


CmsElementBuyBox ​

source code

Render a product including prices, basic information and add to cart button


CmsElementCategoryName ​

source code

Display the category name as the page headline, in the category-heading block. Since Shopware 6.7.12 the default listing layouts use it in place of a text element.

The element is a text element with its own type:

  • Mapped content (by default category.name) is wrapped in <h1 class="cms-element-category-name-headline">, as in the Storefront. When the value does not resolve, for example on a page without a category, no empty headline is rendered.
  • Static content is authored HTML and is rendered as it is.

Rendering goes through CmsElementText, so the vertical alignment, link handling and the cms-element-text typography apply. The root carries the cms-element-category-name class as well.


CmsElementCategoryNavigation ​

source code

Load a navigation menu for current category


CmsElementCrossSelling ​

source code

Render slider of the products from cross-selling setting of a product


CmsElementCustomForm ​

source code

Display a contact or newsletter sign up form


CmsElementForm ​

source code

Display a contact or newsletter sign up form


CmsElementHtml ​

source code


CmsElementImage ​

source code

Display an image for provided media content. Including extra attributes like srcset and alt


CmsElementImageGallery ​

source code

Display a gallery for provided media. Handles a plain image and the spatial (3d) images.


CmsElementImageGallery3dPlaceholder ​

source code


CmsElementImageSlider ​

source code

Display a slider of images


source code

Display a logo of manufacturer of a product


CmsElementProductBox ​

source code

Display a box for provided product


CmsElementProductDescriptionReviews ​

source code

Display a description and reviews for provided product


CmsElementProductListing ​

source code

Display the list of products for currently active listing page


CmsElementProductName ​

source code

Display a name for a product


CmsElementProductSlider ​

source code

Display a slider of provided products


CmsElementSidebarFilter ​

source code

Display a sidebar containing filters for an active product listing


CmsElementText ​

source code

Display a text. Html to Vue mechanism is used to render buttons, links, images accordingly as Vue elements

Styling CMS-authored HTML ​

The rendered container always carries the cms-element-text class. Because the content comes from the Shopware admin editor, its tags (h1–h6, ul, table, img, …) arrive without any classes, so they can only be reached with element selectors — and those must never be declared globally, or they would also hit product names, buttons and other markup you do control.

This layer ships that typography for you in app/assets/css/rich-text.css, registered through css: [] in the layer's nuxt.config.ts. It is plain CSS, so it also works for apps that don't use UnoCSS. Nothing to wire up in your app.

Retheming ​

Every value reads from a --rte-* custom property with a built-in fallback, so you only set the properties you want to change — no need to redeclare the rules:

css
:root {
  --rte-h1-size: 3rem;
  --rte-h1-line: 3.25rem;
  --rte-border-color: var(--color-outline-variant);
}
PropertyDefault
--rte-h1-size / --rte-h1-line2.25rem / 2.5rem
--rte-h2-size / --rte-h2-line1.75rem / 2rem
--rte-h3-size / --rte-h3-line1.25rem / 1.5rem
--rte-h4-size / --rte-h4-line1.125rem / 1.5rem (h4–h6)
--rte-heading-weight600
--rte-heading-mb10px
--rte-flow1rem (spacing between blocks)
--rte-list-indent40px
--rte-cell-padding0.5rem 0.75rem
--rte-border-color#e5e7eb (tables, hr)

Because the properties are inherited, you can also scope them contextually instead of overriding selectors:

css
.cms-block-image-text-cover .cms-element-text {
  --rte-h1-size: 3.5rem;
}
Scope ​

The class is set everywhere admin-authored HTML is injected, so one rule set covers all of them:

ComponentClasses
CmsElementTextcms-element-text
CmsElementHtmlcms-element-html cms-element-text
CmsElementProductDescriptionReviewscms-element-text (description body)
FrontendAccountCustomerGroupRegistrationPagecms-element-text (intro text)

Add cms-element-text to your own wrappers if you render admin HTML elsewhere, for example custom fields using the HTML editor.

Notes ​

The stylesheet uses :where() throughout, which keeps the specificity at (0,1,0). Two consequences worth knowing:

  • A utility class or an inline style set by the editor still wins, without !important.
  • The rules beat a framework reset (ul { list-style: none }) no matter which stylesheet is injected first, so the CSS order does not matter.

A <style scoped> block inside this component would not work: the markup is created by a render function, and Vue only applies the scope id to the container root, not to its descendants.


CmsElementVideo ​

source code

Play a video uploaded to the Shopware media library, in the video block. YouTube and Vimeo videos have their own elements.

Every option of the element in the Administration is supported:

OptionBehaviour
VideoStatic or mapped media. Nothing is rendered when it does not resolve.
Display modestandard keeps the video's size, stretch makes it full width, cover fills the element and crops the video.
Minimum heightApplies to cover only.
Vertical / horizontal alignPositions a standard or stretch video. Ignored for cover.
Play automaticallyAlso mutes the video, because browsers only autoplay muted videos.
Play muted, Play in a loopSet muted and loop.
Play inline on iOS devicesSets playsinline.
Show controlsShows the native controls. Without them the whole element is a play/pause button with a play icon, operable by keyboard too.
Load only after confirmationShows the cover image set for the video in the media module and loads nothing until playback starts. Turns autoplay off. Without a cover image, a stretch video keeps a 16:9 box until it loads.
Screen reader titleNames the video, falling back to the media alt text (and title for the tooltip).

Without controls, the button's name always says what it does: play or pause. The video's name is announced as its description. A video that cannot be loaded, for example in a format the browser does not play or with a missing file, shows an error in place of the play icon and names the button after the error.

The texts can be translated through cmsTranslations:

KeyDefault
cms.video.playLabelPlay video
cms.video.pauseLabelPause video
cms.video.loadErrorThe video could not be loaded.
cms.video.notSupportedYour browser does not support the HTML5 video tag.

CmsElementVimeoVideo ​

source code

Display a player for Vimeo media


CmsElementYoutubeVideo ​

source code

Display a player for YouTube video


SwProductListingPagination ​

source code


CmsSectionDefault ​

source code

Renders a generic block type

See the <CmsPage/> source code to see how it's used


CmsSectionSidebar ​

source code

Renders a generic block type

See the <CmsPage/> source code to see how it's used


ProductCardSkeleton ​

source code


Was this page helpful?
UnsatisfiedSatisfied
Be the first to vote!
0.0 / 5  (0 votes)