No Preview

Sorry, but you either have no stories or none are selected somehow.

If the problem persists, check the browser console, or the terminal you've run Storybook from.

The component failed to render properly, likely due to a configuration issue in Storybook. Here are some common causes and how you can address them:

  1. Missing Context/Providers: You can use decorators to supply specific contexts or providers, which are sometimes necessary for components to render correctly. For detailed instructions on using decorators, please visit the Decorators documentation.
  2. Misconfigured Webpack or Vite: Verify that Storybook picks up all necessary settings for loaders, plugins, and other relevant parameters. You can find step-by-step guides for configuring Webpack or Vite with Storybook.
  3. Missing Environment Variables: Your Storybook may require specific environment variables to function as intended. You can set up custom environment variables as outlined in the Environment Variables documentation.

This is a pre-release version and is not production ready. For new and ongoing projects, please refer to the latest Design System version.

Highlight essential product details and provide an entry point to access in-depth information.

<a href="#" class="card product-card"> <div class="card-body product-navigation"> <h3 class="mb-16">Product</h3> <p class="lead">This is a short description of the product.</p> <span class="link-icon"> <post-icon name="3020" aria-hidden="true"></post-icon> <span>Learn more</span> </span> </div> </a>
NameDescriptionDefaultControl
General
Title
Defines the text in the heading tag.
string
-
Heading Level
Defines the hierarchical level of the product card title within the heading structure.
string
-
Text
Defines the text displayed under the heading tag.
string
-

Make sure the @swisspost/design-system-styles package is already present in your project or follow the installation guidelines.

To import all Design System styles:

@use '@swisspost/design-system-styles/post-compact.scss';

To import only the styles required for this component:

@use '@swisspost/design-system-styles/basics.scss'; @use '@swisspost/design-system-styles/components/card.scss'; @use '@swisspost/design-system-styles/components/product-card.scss';

For organizing multiple product cards in a group, utilize the grid system. Ensure consistent height by applying the .h-full class to all product cards.

For presenting a collection of products with comparable features, use cards with multiple sections, as illustrated in the example below.

Note that this layout necessitates JavaScript implementation to ensure consistent section heights across all cards.

Affordable

Sample Product

With SAMPLE PRODUCT, your letters arrive at their destination cost-effectively and reliably.

Sample Product

140 x 90 mm bis B5 (250 x 176 mm)

bis 500 g
1.20
bis 50 g
2.20
Sample Product

140 x 90 mm bis B5 (250 x 176 mm)

so zwischen ca. 5g
bis ungefähr etwa 500 g
1.20
bis 50 g
2.20
bis 100 g
2.90
bis 100 g
2.90
bis 100 g
2.90
bis 100 g
2.90
Sample Product

140 x 90 mm bis B5 (250 x 176 mm)

bis 500 g
1.20
bis 50 g
2.20
bis 100 g
2.90

Faster

Sample Product

This is a sample description with more detailed information about the product features and benefits. It demonstrates the layout and structure of the product card component.

Sample Product

140 x 90 mm bis B5 (250 x 176 mm)

bis 500 g
1.20
bis 50 g
2.20
bis 100 g
2.90
Sample Product

140 x 90 mm bis B5 (250 x 176 mm)

so zwischen ca. 5g
bis ungefähr etwa 500 g
1.20
bis 50 g
2.20
bis 100 g
2.90
Sample Product

140 x 90 mm bis B5 (250 x 176 mm)

bis 500 g
1.20
bis 50 g
2.20
bis 100 g
2.90
Vanilla JavaScript
function syncHeights() { const nodes = document.querySelectorAll('[data-sync-height-with]'); const heightByGroup = new Map(); nodes.forEach(node => { const group = node.getAttribute('data-sync-height-with'); const groupHeight = heightByGroup.get(group); node.style.height = 'auto'; const nodeHeight = node.offsetHeight; if (!groupHeight || nodeHeight > groupHeight) { heightByGroup.set(group, nodeHeight); } }); heightByGroup.forEach((height, group) => { const groupNodes = document.querySelectorAll( `[data-sync-height-with="${group}"]` ); groupNodes.forEach(node => { node.style.height = `${height}px`; }); }); } let timer; window.addEventListener('resize', () => { if (timer) clearTimeout(timer); timer = setTimeout(() => { syncHeights(); }, 300); }); syncHeights();
Angular Implementation
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core'; import { debounceTime, Subject } from 'rxjs'; @Component({ selector: 'post-product-cards', templateUrl: './post-product-cards.component.html', }) export class PostProductCardsComponent implements OnInit, OnDestroy { resize$ = new Subject<void>(); ngOnInit() { this.resize$ .asObservable() .pipe(debounceTime(300)) .subscribe(() => { this.syncHeight(); }); this.resize$.next(); } ngOnDestroy() { this.resize$.complete(); } syncHeight() { const nodes: NodeListOf<HTMLElement> = document.querySelectorAll('[data-sync-height-with]'); const heightByGroup = new Map<string, number>(); nodes.forEach(node => { const group = node.getAttribute('data-sync-height-with'); const groupHeight = heightByGroup.get(group); const nodeHeight = node.offsetHeight; if (!groupHeight || nodeHeight > groupHeight) { heightByGroup.set(group, nodeHeight); } }); heightByGroup.forEach((height, group) => { const groupNodes: NodeListOf<HTMLElement> = document.querySelectorAll( `[data-sync-height-with="${group}"]`, ); groupNodes.forEach(node => { node.style.height = `${height}px`; }); }); } @HostListener('window:resize') onResize(): void { this.resize$.next(); } }