Skip to content
Shopware

shopware/frontends - cms-base

shopware/frontends - cms-base

Nuxt layer that provides an implementation of all CMS components in Shopware based on utility-classes using atomic css syntax (UnoCss / Tailwind).

It is useful for projects that want to use the CMS components but design their own layout.

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 install -D @shopware/cms-base-layer

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

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

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

ts
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
  extends: ["@shopware/composables/nuxt-layer", "@shopware/cms-base-layer"],
  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>

You can use default styling by installing/importing Tailwind CSS stylesheet in your project.

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

Default styling

The components are styled using Tailwind CSS utility classes, so you can use them in your project without any additional configuration if your project uses Tailwind CSS.

This layer provides a default Tailwind CSS configuration (see uno.config.ts for details), which is used to style the components. If you want to customize the styling, you can do so by creating your own Tailwind CSS configuration file and extending the default one:

ts
// nuxt.config.ts
export default defineNuxtConfig({
  // ...
  unocss: {
    nuxtLayers: true, // enable Nuxt layers for UnoCSS
  },
})
ts
// uno.config.ts
import config from './.nuxt/uno.config.mjs'

export default config

Thanks to this, you can use the default configuration provided by this layer, or extend/overwrite it with your own customizations in your end-project:

ts
// uno.config.ts
import { mergeConfigs } from '@unocss/core'
import config from './.nuxt/uno.config.mjs'

export default mergeConfigs([config, {
  theme: {
    colors: {
      primary: '#ff3e00',
      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="product.cover.media.alt"
/>

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',
        }
      }
    }
  }
})

📘 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 into ~/components dir in your nuxt project (or wherever according your nuxt config)

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

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: 1.5.1

Patch Changes

  • #1879 eaf170b Thanks @acuriouspotion! - Fix youtube player control display and usage of advanced privacy mode setting.

  • #1862 20fd2c6 Thanks @aheartforspinach! - Fix CmsSectionSidebar.vue when used on a landing page by removing useCategory and related code

  • #1884 3004b97 Thanks @MorennMcFly! - Fix cms blocks TextTeaserSection and TextTwoColumn responsivity so the elements stack from md breakpoint and under.

  • #1863 f8c5cd5 Thanks @aheartforspinach! - move CmsBlockHtml.vue to block folder (instead of element), remove CmsBlockHtml.md

  • Updated dependencies [ab040bb, c8fa438]:

    • @shopware/composables@1.9.1
    • @shopware/helpers@1.5.0

Available components

CmsGenericBlock

source code

Renders a Block type structure

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

Example usage:

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

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

const { getSlotContent } = useCmsBlock(props.content);
const rightContent = getSlotContent("right");
const leftContent = 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

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>

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


CmsBlockVimeoVideo

source code


CmsBlockYoutubeVideo

source code


CmsElementBuyBox

source code

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


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


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