OTTODesign System

Code

Selection Tile

Storybook group: Components · Sidebar path: Components/Selection Tile · Extracted 28.09.2026

Version Tag Status API
v2 <oc-selection-tile-v2> Stable, allowed for generation SelectionTileV2
v1 <oc-selection-tile-v1> Deprecated, NOT allowed for generation SelectionTileV1

Only the latest version (v2) is allowed for generation. Older versions are kept for reference and are deprecated.

Overview (v2)

Source: ./src/components/selection-tile/v2/Overview.mdx

Selection tile

The selection tile component presents selectable tiles for text, color, image, or custom-content variants. Use it to visualize size charts, palette pickers, or product configurations while keeping native form controls in sync.

Default variation

Story Default:

<oc-selection-tile-v2 variant="text">
  <label slot="content">label</label>
  <input type="checkbox" aria-label="oc-auto"/>
</oc-selection-tile-v2>

Configuration

The selection tile component offers a variety of styling variants such as color, container, image, and text. This component is configurable, allowing you to tailor its features and appearance to your specific needs. To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the selection tile component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.

Info

See the Selection tile UX documentation for detailed user experience guidelines.

Layout considerations

Visual Overflow:

This component has visual overflow. It extends beyond its bounding box and is clipped by parent containers with overflow: hidden. Ensure the parent container has sufficient padding to accommodate the component's full visual area.

Extended Hitbox:

This component has an extended hitbox. The touch area extends beyond its bounding box, so it may be activated when the user clicks or taps outside the visible component area. Ensure sufficient margin around the component to prevent unintended interactions with adjacent elements.

Accessibility

The selection tile component relies on the slotted input, so pass aria-label, name, value, checked, and disabled states directly to the control. Reference the built-in accessibility features guide for focus management and keyboard interactions. To improve screen-reader output, describe color and image variants with concise text alternatives.

Configuration (v2)

Source: ./src/components/selection-tile/v2/Configuration.mdx

Selection tile configuration

Configure the selection tile component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

Story Default:

<oc-selection-tile-v2 variant="text">
  <label slot="content">label</label>
  <input type="checkbox" aria-label="oc-auto"/>
</oc-selection-tile-v2>

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

Migration (v2)

Source: ./src/components/selection-tile/v2/Migration.mdx

Migration from selection tile v1 to v2

The oc-selection-tile component has been updated from oc-selection-tile-v1 to oc-selection-tile-v2. This migration guide provides step-by-step instructions to update your project to the latest version.

Skip to:

What's new

Native input element

The component now uses a native <input> element, providing:

  • Better form integration and native form submission
  • Native validation support
  • Improved accessibility with screen readers
  • Support for standard input attributes like autofocus, form, formnovalidate
Selection behavior via input type
  • Use <input type="checkbox"> for multi-selection (multiple tiles can be selected)
  • Use <input type="radio"> with matching name attributes for single-selection (only one tile in the group can be selected)
Events

All native input events are now available:

  • click
  • input
  • change
  • focus
  • blur
Flexible content

The content slot allows for more flexible content, including HTML elements:

<oc-selection-tile-v2 variant="container">
  <input type="checkbox" name="option" value="custom" aria-label="oc-auto" />
  <div slot="content" style="display: flex; flex-direction: column; gap: 8px; padding: 16px;">
    <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
    <span class="oc-copy-125">Custom option</span>
  </div>
</oc-selection-tile-v2>

API changes

Changed attributes
v1 Attribute v2 Attribute Notes
fill-parent width-behavior="fill" Default is "fit"
variant variant No change
color color No change
img-src img-src No change
strike-through strike-through No change
Changed slots
v1 Slot v2 Slot Notes
default (content) content Content now uses the content slot
— default Now contains the native <input> element
Removed attributes

The following attributes have been removed and should now be set on the native <input> element:

v1 Attribute v2 Equivalent Notes
checked Set checked on the <input> element Moved to native input
disabled Set disabled on the <input> element Moved to native input
name Set name on the <input> element Moved to native input
value Set value on the <input> element Moved to native input
oc-aria-label Set aria-label on the <input> element Renamed to standard attribute
single-selection Use <input type="radio"> instead of <input type="checkbox"> Use appropriate input type
Removed CSS variables
v1 CSS Variable v2 Equivalent Notes
--color Use the color attribute instead Replaced with attribute

How to migrate

The main change is that v2 uses a native <input> element in the default slot instead of managing the selection state internally. Use type="checkbox" for multi-selection scenarios or type="radio" for single-selection scenarios. This provides better accessibility, form integration, and native event support.

Migrate the text variant (multi-selection)
<!-- From: -->
<oc-selection-tile-v1 variant="text" name="size" value="M">M</oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2 variant="text">
  <input type="checkbox" name="size" value="M" aria-label="oc-auto" />
  <label slot="content">M</label>
</oc-selection-tile-v2>
Migrate the text variant (single-selection)
<!-- From: -->
<oc-selection-tile-v1 variant="text" name="size" value="M" single-selection>M</oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2 variant="text">
  <input type="radio" name="size" value="M" aria-label="oc-auto" />
  <label slot="content">M</label>
</oc-selection-tile-v2>
Migrate the color variant
<!-- From: -->
<oc-selection-tile-v1
  variant="color"
  color="#ffddd2"
  name="color"
  value="peachy"
  oc-aria-label="Peachy pink"
></oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2 variant="color" color="#ffddd2">
  <input type="checkbox" name="color" value="peachy" aria-label="Peachy pink" />
</oc-selection-tile-v2>
Migrate the image variant
<!-- From: -->
<oc-selection-tile-v1
  variant="image"
  img-src="/path/to/image.png"
  name="product"
  value="variant-1"
  oc-aria-label="Product variant 1"
></oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2 variant="image" img-src="/path/to/image.png">
  <input type="checkbox" name="product" value="variant-1" aria-label="Product variant 1" />
</oc-selection-tile-v2>
Migrate the container variant
<!-- From: -->
<oc-selection-tile-v1 variant="container" name="option" value="custom">
  <div>Custom content</div>
</oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2 variant="container">
  <input type="checkbox" name="option" value="custom" aria-label="oc-auto" />
  <div slot="content">Custom content</div>
</oc-selection-tile-v2>
Migrate a selection tile with a disabled state
<!-- From: -->
<oc-selection-tile-v1 disabled>Label</oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2>
  <input type="checkbox" disabled aria-label="oc-auto" />
  <label slot="content">Label</label>
</oc-selection-tile-v2>
Migrate a selection tile with width behavior
<!-- From: -->
<oc-selection-tile-v1 fill-parent>Full width</oc-selection-tile-v1>
<!-- To: -->
<oc-selection-tile-v2 width-behavior="fill">
  <input type="checkbox" aria-label="oc-auto" />
  <label slot="content">Full width</label>
</oc-selection-tile-v2>
Migrate a group of single-selection tiles
<!-- From: -->
<fieldset>
  <legend>Size</legend>
  <oc-selection-tile-v1 variant="text" name="size" value="S" single-selection
    >S</oc-selection-tile-v1
  >
  <oc-selection-tile-v1 variant="text" name="size" value="M" single-selection
    >M</oc-selection-tile-v1
  >
  <oc-selection-tile-v1 variant="text" name="size" value="L" single-selection
    >L</oc-selection-tile-v1
  >
</fieldset>
<!-- To: -->
<fieldset role="radiogroup" aria-label="Size">
  <oc-selection-tile-v2 variant="text">
    <input type="radio" name="size" value="S" aria-label="oc-auto" />
    <label slot="content">S</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 variant="text">
    <input type="radio" name="size" value="M" aria-label="oc-auto" />
    <label slot="content">M</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 variant="text">
    <input type="radio" name="size" value="L" aria-label="oc-auto" />
    <label slot="content">L</label>
  </oc-selection-tile-v2>
</fieldset>

API v1 (v1, deprecated, not for generation)

Source: ./src/components/selection-tile/v1/SelectionTileV1.API.g.mdx

Selection Tile v1 API

API: <oc-selection-tile-v1> (SelectionTileV1)

The Selection Tile component provides an interactive tile with properties for setting the variant, disabled state, initial checked state, and form identification and processing values. It supports both single and multi-selection behaviors, acting as a radio button for single selections and a checkbox for multiple selections.

Attributes / properties
Attribute Type Default Required Description
variant "text" | "color" | "container" | "image" "text" no Sets the main styling and behavior of the selection tile. Can be one of: color, container, image, text.
single-selection boolean false no Specifies whether only one selection tile can be selected at once. Requires the attributes name and value to be set.
value string "on" no Specifies the value of a checked selection tile for form processing. If this attribute is not specified, the default value on is used as the submitted data.

Mandatory if single-selection is active.
color string undefined no Deprecated: The attribute color is deprecated. Please use the CSS-Variable --color instead.

The color value of the selection tile displayed as a circular swatch. Accepts any valid CSS color value, including hex codes (e.g., #ffddd2), RGB values, or CSS gradients. Only applies when variant="color".
img-src string undefined no Specifies the URL of the image. This attribute only applies to variant="image".
strike-through boolean false no Specifies whether the selection tile should render a 45° diagonal line on top of the content
checked boolean no Toggles the state of the selection tile between checked and unchecked. When set to true, the selection tile is initially displayed as checked.
disabled boolean no Disables the selection tile, preventing user interaction and input.
fill-parent boolean false no Sets the width of the selection tile to match the width of the parent element.
name string undefined no Sets the name attribute to identify the selection tile when submitting a form.
oc-aria-label string undefined no Sets the ARIA label of the selection tile.
Slots
Slot Required Description
default no Sets the text content of the selection tile. This slot is only available to variant="text" and variant="container".
Events
Event Detail type Description
oc-property-change OcSelectionTileV1Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
CSS custom properties
Custom property Default Description
--color undefined Sets the color of the selection tile.

Only applies when variant="color" is set.

Note: The preferred way of using colors is via design tokens instead of hex values.

API v2

Source: ./src/components/selection-tile/v2/SelectionTileV2.API.g.mdx

Selection Tile v2 API

API: <oc-selection-tile-v2> (SelectionTileV2)

The Selection Tile component allows users to select one or more options with various visual representations. Supports multiple variants (text, color, image, and container) for different use cases like size selection, color picking, and product variants.

Attributes / properties
Attribute Type Default Required Description
variant "text" | "color" | "container" | "image" "text" no The main styling and behavior variant of the selection tile. - text: Displays text content from the default slot - color: Displays a colored circle using the color attribute - image: Displays an image using the img-src attribute - container: Displays custom content from the default slot with container styling
color string undefined no Deprecated: The attribute color is deprecated. Please use the CSS-Variable --color instead.

The color value of the selection tile displayed as a circular swatch. Accepts any valid CSS color value, including hex codes (e.g., #ffddd2), RGB values, or CSS gradients. Only applies when variant="color".
img-src string undefined no The URL of the image to display. This attribute applies only when variant="image".
strike-through boolean false no Indicates whether the selection tile displays a diagonal strike-through line. When true, overlays a 45-degree line across the content to indicate unavailable or discontinued options. When false, displays normal content without any strike-through. Compatible with all variants.
width-behavior "fill" | "fit" "fit" no Defines the width behavior of the radio button component. - "fill": The component expands to fill the available width. - "fit": The component width fits its content.

Only applies when variant="container" or variant="text".
Slots
Slot Required Description
default yes Requires one of the following interactive elements: - <input type="checkbox"> for multi-selection - <input type="radio"> for single-selection

For more information on interactive components, refer to the interactive component slots documentation.
content no The text or HTML content displayed inside the selection tile. For variant="text", typically contains a <label slot="content"> element with the option text. For variant="container", can contain any custom HTML markup such as images, icons, or complex layouts. Not used for variant="color" or variant="image" as these variants display colors and images via attributes.
Events
Event Detail type Description
oc-property-change OcSelectionTileV2Events["oc-property-change"] Whenever a property value changes, this event triggers. Use this event to track all property changes within the component.

Refer to the Events documentation for more information.
oc-mount { component: string; } Fired when the component is mounted to the DOM. The event is fired when the onMount hook of the component is called by the runtime.
oc-unmount { component: string; } Fired when the component is unmounted from the DOM. The event is fired when the function returned by the onMount hook of the component is called by the runtime.
CSS custom properties
Custom property Default Description
--color undefined The color value of the selection tile displayed as a circular swatch. Accepts any valid CSS color value, including hex codes (e.g., #ffddd2), RGB values, or CSS gradients. Only applies when variant="color" is set.

Note: The preferred way of using colors is via design tokens instead of hex values.

Variations (v2)

Source: ./src/components/selection-tile/v2/Variations.mdx

Variations

Listed below are the most common variations of the selection tile component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-selection-tile-variations--default · tags: components

The default text variant displaying a simple label. Use this variant for text-based options like clothing sizes, measurements, or short descriptive labels. The text content is provided via the default slot, typically wrapped in a <label slot="content"> element.

Args: variant=text

<oc-selection-tile-v2 variant="text">
  <label slot="content">label</label>
  <input type="checkbox" aria-label="oc-auto"/>
</oc-selection-tile-v2>

Color

Story: components-selection-tile-variations--color · tags: components

The color variant displays a circular color swatch using the --color CSS variable. Ideal for color selection use cases where users need to choose from available product colors. Accepts any valid CSS color value including hex codes, RGB, HSL, or named colors. Since there's no visible text, the input element must include a descriptive aria-label for accessibility. Content in the default slot is not displayed in this variant.

Args: variant=color, --color=#ffddd2, defaultSlot=<input type="checkbox" aria-label="Example of a selection tile of variant color with a peachy pink color"/>, contentSlot=``

<oc-selection-tile-v2 variant="color" style="--color: #ffddd2">
  <input type="checkbox" aria-label="Example of a selection tile of variant color with a peachy pink color"/>
</oc-selection-tile-v2>

Color with gradient

Story: components-selection-tile-variations--color-gradient · tags: components

The color variant with CSS gradient support. Demonstrates how to use CSS linear gradients for more complex color patterns. Accepts any valid CSS gradient syntax including linear-gradient, radial-gradient, and conic-gradient. Perfect for showing multicolor or patterned options. Since there's no visible text, the input element must include a descriptive aria-label for accessibility.

Args: variant=color, defaultSlot=<input type="checkbox" aria-label="Rainbow gradient"/>, contentSlot=``, --color=linear-gradient( 45deg, #d94543 15%, #cfcf4d 30%, #69cb64 45%, #2a86b4 60%, #5f5fd0 75%, #da67da 90% )

<oc-selection-tile-v2 variant="color" style="--color: linear-gradient(
  45deg,
  #d94543 15%,
  #cfcf4d 30%,
  #69cb64 45%,
  #2a86b4 60%,
  #5f5fd0 75%,
  #da67da 90%
)">
  <input type="checkbox" aria-label="Rainbow gradient"/>
</oc-selection-tile-v2>

Image

Story: components-selection-tile-variations--image · tags: components

The image variant displays a circular image using the img-src attribute. Ideal for showing product variants, patterns, textures, or visual previews. The image is automatically cropped to a circular shape and centered. Since there's no visible text, the input element must include a descriptive aria-label for accessibility. Content in the default slot is not displayed in this variant.

Args: variant=image, img-src=https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png, defaultSlot=<input type="checkbox" aria-label="Example of a selection tile of variant image with a placeholder image"/>, contentSlot=``

<oc-selection-tile-v2 variant="image" img-src="https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png">
  <input type="checkbox" aria-label="Example of a selection tile of variant image with a placeholder image"/>
</oc-selection-tile-v2>

Strike through

Story: components-selection-tile-variations--strike-through · tags: components

The text variant with strike-through enabled. Displays a diagonal line across the selection tile to indicate unavailable, out-of-stock, or discontinued options. The strike-through automatically adjusts to the tile's dimensions. Users can still interact with struck-through tiles unless they are also disabled.

Args: strike-through=true

<oc-selection-tile-v2 strike-through>
  <label slot="content">label</label>
  <input type="checkbox" aria-label="oc-auto"/>
</oc-selection-tile-v2>

Strike through color

Story: components-selection-tile-variations--strike-through-color · tags: components

The color variant with strike-through enabled. Demonstrates how the strike-through indicator works with color swatches. Useful for showing discontinued or unavailable color options.

Args: variant=color, strike-through=true, defaultSlot=(see snippet), contentSlot=``, --color=#ffddd2

<oc-selection-tile-v2 variant="color" strike-through style="--color: #ffddd2">
  <input type="checkbox" aria-label="Example of a selection tile of variant color with a peachy pink color and a strike-through"/>
</oc-selection-tile-v2>

Disabled

Story: components-selection-tile-variations--disabled · tags: components

The disabled state prevents user interaction with the selection tile. A visual overlay is applied to indicate the disabled state. The disabled attribute must be set on the input element, not on the oc-selection-tile-v2 element. Disabled tiles cannot be selected or deselected by users.

Args: variant=text, defaultSlot=<input type="checkbox" disabled aria-label="oc-auto"/>

<oc-selection-tile-v2 variant="text">
  <label slot="content">label</label>
  <input type="checkbox" disabled aria-label="oc-auto"/>
</oc-selection-tile-v2>

Container

Story: components-selection-tile-variations--container · tags: components

The container variant for displaying custom content in the default slot. Provides a flexible rectangular container with rounded corners. Use this variant for complex content like:

  • Product cards with images and descriptions
  • Multi-line text with icons
  • Custom layouts with multiple elements

Args: variant=container, contentSlot=(see snippet)

<oc-selection-tile-v2 variant="container">
  <!-- Wrapper for custom width.-->
      <div slot="content" style="display:flex;flex-direction: column; gap: 8px; padding: 16px;">
        <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
          <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
          <span class="oc-copy-125">Some custom content</span>
        </div>
        
        <span
        class="oc-copy-50 oc-text-color-secondary" 
          style="padding-left: 35px;"
        >
          Additional information
        </span>
      </div>
  <input type="checkbox" aria-label="oc-auto"/>
</oc-selection-tile-v2>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Container",
  args: {
    variant: "container",
    contentSlot: `<!-- Wrapper for custom width.-->
    <div slot="content" style="display:flex;flex-direction: column; gap: 8px; padding: 16px;">
      <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
        <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
        <span class="oc-copy-125">Some custom content</span>
      </div>
      
      <span
      class="oc-copy-50 oc-text-color-secondary" 
        style="padding-left: 35px;"
      >
        Additional information
      </span>
    </div>`
  }
}

Container with placeholder

Story: components-selection-tile-variations--container-with-placeholder · tags: components

The container variant with a placeholder component as content. Demonstrates how to use placeholder elements during development or for content-to-be-determined scenarios.

Args: variant=container, defaultSlot=(see snippet)

<oc-selection-tile-v2 variant="container">
  <label slot="content">label</label>
  <oc-placeholder-v1 slot="content" style="display: flex;
      width: 165px;
      height: 80px;
      justify-content: center;
      align-items: center;
      flex-shrink: 0;
      opacity: 0.4;
      border-radius: 8px;
      background: #30D9BA;
      color: #fff;
      font-weight: 700;
      padding: 8px;
      ">PLACEHOLDER</oc-placeholder-v1>
</oc-selection-tile-v2>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Container with placeholder",
  args: {
    variant: "container",
    defaultSlot: `<oc-placeholder-v1 slot="content" style="display: flex;
    width: 165px;
    height: 80px;
    justify-content: center;
    align-items: center;
    flex-shrink: 0;
    opacity: 0.4;
    border-radius: 8px;
    background: #30D9BA;
    color: #fff;
    font-weight: 700;
    padding: 8px;
    ">PLACEHOLDER</oc-placeholder-v1>`
  }
}

Container with image

Story: components-selection-tile-variations--container-with-image · tags: components

The container variant with an image element as content. Demonstrates how to display product images with custom dimensions and styling. Unlike the image variant (which displays circular images), the container variant allows rectangular images with custom aspect ratios.

Args: variant=container, defaultSlot=<input type="checkbox" aria-label="oc-auto"/>, contentSlot=(see snippet)

<oc-selection-tile-v2 variant="container">
  <div>
      <img
        alt="Placeholder image"
        src="https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png"
        style="display: block; width: 64px; height: 80px;"
      />
    </div>
  <input type="checkbox" aria-label="oc-auto"/>
</oc-selection-tile-v2>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Container with image",
  args: {
    variant: "container",
    defaultSlot: `<input type="checkbox" aria-label="oc-auto"/>`,
    contentSlot: `<div>
    <img
      alt="Placeholder image"
      src="${placeholderImage}"
      style="display: block; width: 64px; height: 80px;"
    />
  </div>`
  }
}

Demo: single-selection

Story: components-selection-tile-variations--demo-single-selection · tags: components

A comprehensive demo showcasing single-selection behavior across all variants. Demonstrates how radio buttons enable mutually exclusive selection within each group. Each variant group uses radio inputs with matching name attributes to ensure only one option can be selected per group. Note the use of role="radiogroup" and aria-label on wrapper elements for proper accessibility.

<div class="demo-single-selection-group">
  <h2>Variant Text</h2>
  <div class="demo-single-selection" role="radiogroup" aria-label="Select a size">
    <oc-selection-tile-v2>
      <input type="radio" aria-label="oc-auto" name="size" value="S" />
      <label slot="content">S</label>
    </oc-selection-tile-v2>

    <oc-selection-tile-v2>
      <input type="radio" aria-label="oc-auto" name="size" value="M" checked />
      <label slot="content">M</label>
    </oc-selection-tile-v2>

    <oc-selection-tile-v2>
      <input type="radio" aria-label="oc-auto" name="size" value="L" />
      <label slot="content">L</label>
    </oc-selection-tile-v2>

    <oc-selection-tile-v2>
      <input type="radio" aria-label="oc-auto" name="size" value="XL" />
      <label slot="content">XL</label>
    </oc-selection-tile-v2>

    <oc-selection-tile-v2>
      <input type="radio" aria-label="oc-auto" name="size" value="XXL" />
      <label slot="content">XXL</label>
    </oc-selection-tile-v2>
  </div>
  <br />
  <h2>Variant Color</h2>
  <div class="demo-single-selection" role="radiogroup" aria-label="Select a color">
    <oc-selection-tile-v2 variant="color" color="#006d77">
      <input
        type="radio"
        name="color"
        variant="color"
        value="#006d77"
        aria-label="ocean blue"
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2 variant="color" color="#83c5be">
      <input
        type="radio"
        name="color"
        variant="color"
        value="#83c5be"
        aria-label="soft green"
        checked
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2 variant="color" color="#edf6f9">
      <input
        type="radio"
        name="color"
        variant="color"
        value="#edf6f9"
        aria-label="light blue"
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2 variant="color" color="#ffddd2">
      <input
        type="radio"
        name="color"
        variant="color"
        value="#ffddd2"
        aria-label="peachy pink"
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2 variant="color" color="#e29578">
      <input
        type="radio"
        name="color"
        variant="color"
        value="#e29578"
        aria-label="warm brown"
      />
    </oc-selection-tile-v2>
  </div>
  <br />
  <h2>Variant Image</h2>
  <div
    class="demo-single-selection"
    role="radiogroup"
    aria-label="Select the color of the sneaker"
  >
    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
    >
      <input
        type="radio"
        name="sneaker"
        value="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
        aria-label="White sneaker with three blue stripes"
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
    >
      <input
        type="radio"
        name="sneaker"
        value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
        aria-label="Dark green sneaker with three white stripes"
        checked
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
    >
      <input
        type="radio"
        name="sneaker"
        value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
        aria-label="Dark red sneaker with three white stripes"
      />
    </oc-selection-tile-v2>

    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
    >
      <input
        type="radio"
        name="sneaker"
        value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
        aria-label="Dark blue and black sneaker with three white stripes"
      />
    </oc-selection-tile-v2>
  </div>

  <br />
  <h2>Variant Container</h2>
  <h3>Fit content</h3>
  <div
    class="demo-single-selection"
    role="radiogroup"
    aria-label="Select the color of the longsleeve"
  >
    <oc-selection-tile-v2 variant="container">
      <input type="radio" aria-label="oc-auto" name="shirt" value="random1" />
      <img
        slot="content"
        alt="Orange longsleeve"
        src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="radio" aria-label="oc-auto" name="shirt" value="random2" checked />
      <img
        slot="content"
        alt="Blue longsleeve"
        src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="radio" aria-label="oc-auto" name="shirt" value="random3" />
      <img
        slot="content"
        alt="Black longsleeve"
        src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="radio" aria-label="oc-auto" name="shirt" value="random4" />
      <img
        slot="content"
        alt="Dark red longsleeve"
        src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
  </div>
  <h3>Custom width</h3>
  <div class="demo-single-selection" role="radiogroup" aria-label="Select random content">
    <oc-selection-tile-v2 variant="container">
      <input type="radio" aria-label="Some custom content" name="random" value="random1" />
      <div
        slot="content"
        style="display:flex; flex-direction: column; gap: 8px; padding: 16px; width: 100%;"
      >
        <div style="display:flex; flex-direction: row; gap: 12px; align-items:center;">
          <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
          <span class="oc-copy-125">Some custom content</span>
        </div>
        <span class="oc-copy-50 oc-text-color-secondary" style=" padding-left: 35px; ">
          Additional information
        </span>
      </div>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input
        type="radio"
        aria-label="Other custom content"
        name="random"
        value="random2"
        checked
      />
      <div
        slot="content"
        style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
      >
        <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
        <span class="oc-copy-125">Other custom content</span>
      </div>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="radio" aria-label="More content" name="random" value="random3" />
      <div
        slot="content"
        style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
      >
        <span class="oc-copy-125">More content</span>
      </div>
    </oc-selection-tile-v2>
  </div>

  <style>
    .demo-single-selection-group {
      display: flex;
      flex-direction: column;
      gap: 10px;
    }

    .demo-single-selection {
      display: flex;
      gap: 8px;
      align-items: start;
    }
  </style>
</div>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: single-selection",
  render() {
    return html` <div class="demo-single-selection-group">
      <h2>Variant Text</h2>
      <div class="demo-single-selection" role="radiogroup" aria-label="Select a size">
        <oc-selection-tile-v2>
          <input type="radio" aria-label="oc-auto" name="size" value="S" />
          <label slot="content">S</label>
        </oc-selection-tile-v2>

        <oc-selection-tile-v2>
          <input type="radio" aria-label="oc-auto" name="size" value="M" checked />
          <label slot="content">M</label>
        </oc-selection-tile-v2>

        <oc-selection-tile-v2>
          <input type="radio" aria-label="oc-auto" name="size" value="L" />
          <label slot="content">L</label>
        </oc-selection-tile-v2>

        <oc-selection-tile-v2>
          <input type="radio" aria-label="oc-auto" name="size" value="XL" />
          <label slot="content">XL</label>
        </oc-selection-tile-v2>

        <oc-selection-tile-v2>
          <input type="radio" aria-label="oc-auto" name="size" value="XXL" />
          <label slot="content">XXL</label>
        </oc-selection-tile-v2>
      </div>
      <br />
      <h2>Variant Color</h2>
      <div class="demo-single-selection" role="radiogroup" aria-label="Select a color">
        <oc-selection-tile-v2 variant="color" color="#006d77">
          <input
            type="radio"
            name="color"
            variant="color"
            value="#006d77"
            aria-label="ocean blue"
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2 variant="color" color="#83c5be">
          <input
            type="radio"
            name="color"
            variant="color"
            value="#83c5be"
            aria-label="soft green"
            checked
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2 variant="color" color="#edf6f9">
          <input
            type="radio"
            name="color"
            variant="color"
            value="#edf6f9"
            aria-label="light blue"
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2 variant="color" color="#ffddd2">
          <input
            type="radio"
            name="color"
            variant="color"
            value="#ffddd2"
            aria-label="peachy pink"
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2 variant="color" color="#e29578">
          <input
            type="radio"
            name="color"
            variant="color"
            value="#e29578"
            aria-label="warm brown"
          />
        </oc-selection-tile-v2>
      </div>
      <br />
      <h2>Variant Image</h2>
      <div
        class="demo-single-selection"
        role="radiogroup"
        aria-label="Select the color of the sneaker"
      >
        <oc-selection-tile-v2
          variant="image"
          img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
        >
          <input
            type="radio"
            name="sneaker"
            value="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
            aria-label="White sneaker with three blue stripes"
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2
          variant="image"
          img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
        >
          <input
            type="radio"
            name="sneaker"
            value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
            aria-label="Dark green sneaker with three white stripes"
            checked
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2
          variant="image"
          img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
        >
          <input
            type="radio"
            name="sneaker"
            value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
            aria-label="Dark red sneaker with three white stripes"
          />
        </oc-selection-tile-v2>

        <oc-selection-tile-v2
          variant="image"
          img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
        >
          <input
            type="radio"
            name="sneaker"
            value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
            aria-label="Dark blue and black sneaker with three white stripes"
          />
        </oc-selection-tile-v2>
      </div>

      <br />
      <h2>Variant Container</h2>
      <h3>Fit content</h3>
      <div
        class="demo-single-selection"
        role="radiogroup"
        aria-label="Select the color of the longsleeve"
      >
        <oc-selection-tile-v2 variant="container">
          <input type="radio" aria-label="oc-auto" name="shirt" value="random1" />
          <img
            slot="content"
            alt="Orange longsleeve"
            src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
            style="display: block;"
          />
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 variant="container">
          <input type="radio" aria-label="oc-auto" name="shirt" value="random2" checked />
          <img
            slot="content"
            alt="Blue longsleeve"
            src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
            style="display: block;"
          />
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 variant="container">
          <input type="radio" aria-label="oc-auto" name="shirt" value="random3" />
          <img
            slot="content"
            alt="Black longsleeve"
            src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
            style="display: block;"
          />
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 variant="container">
          <input type="radio" aria-label="oc-auto" name="shirt" value="random4" />
          <img
            slot="content"
            alt="Dark red longsleeve"
            src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
            style="display: block;"
          />
        </oc-selection-tile-v2>
      </div>
      <h3>Custom width</h3>
      <div class="demo-single-selection" role="radiogroup" aria-label="Select random content">
        <oc-selection-tile-v2 variant="container">
          <input type="radio" aria-label="Some custom content" name="random" value="random1" />
          <div
            slot="content"
            style="display:flex; flex-direction: column; gap: 8px; padding: 16px; width: 100%;"
          >
            <div style="display:flex; flex-direction: row; gap: 12px; align-items:center;">
              <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
              <span class="oc-copy-125">Some custom content</span>
            </div>
            <span class="oc-copy-50 oc-text-color-secondary" style=" padding-left: 35px; ">
              Additional information
            </span>
          </div>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 variant="container">
          <input
            type="radio"
            aria-label="Other custom content"
            name="random"
            value="random2"
            checked
          />
          <div
            slot="content"
            style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
          >
            <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
            <span class="oc-copy-125">Other custom content</span>
          </div>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 variant="container">
          <input type="radio" aria-label="More content" name="random" value="random3" />
          <div
            slot="content"
            style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
          >
            <span class="oc-copy-125">More content</span>
          </div>
        </oc-selection-tile-v2>
      </div>

      <style>
        .demo-single-selection-group {
          display: flex;
          flex-direction: column;
          gap: 10px;
        }

        .demo-single-selection {
          display: flex;
          gap: 8px;
          align-items: start;
        }
      </style>
    </div>`;
  }
}

Demo: multi selection

Story: components-selection-tile-variations--demo-multi-selection · tags: components

A comprehensive demo showcasing multi-selection behavior across all variants. Demonstrates how checkboxes allow multiple options to be selected simultaneously within each group. Each variant group uses checkbox inputs to allow multiple selections. Note the use of <fieldset> and aria-label on wrapper elements for proper accessibility grouping.

<div class="demo-multi-selection-group">
  <h2>Variant Text</h2>
  <fieldset class="demo-multi-selection" aria-label="Select a size">
    <oc-selection-tile-v2>
      <input type="checkbox" aria-label="S" name="size" value="S" />
      <label slot="content">S</label>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2>
      <input type="checkbox" aria-label="M" name="size" value="M" checked />
      <label slot="content">M</label>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2>
      <input type="checkbox" aria-label="L" name="size" value="L" />
      <label slot="content">L</label>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2>
      <input type="checkbox" aria-label="XL" name="size" value="XL" />
      <label slot="content">XL</label>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2>
      <input type="checkbox" aria-label="XXL" name="size" value="XXL" />
      <label slot="content">XXL</label>
    </oc-selection-tile-v2>
  </fieldset>
  <br />
  <h2>Variant Color</h2>
  <fieldset class="demo-multi-selection" aria-label="Select a color">
    <oc-selection-tile-v2 variant="color" color="#006d77">
      <input type="checkbox" aria-label="ocean blue" name="color" value="#006d77" />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="color" color="#83c5be">
      <input type="checkbox" aria-label="soft green" name="color" value="#83c5be" checked />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="color" color="#edf6f9">
      <input type="checkbox" aria-label="light blue" name="color" value="#edf6f9" />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="color" color="#ffddd2">
      <input type="checkbox" aria-label="peachy pink" name="color" value="#ffddd2" />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="color" color="#e29578">
      <input type="checkbox" aria-label="warm brown" name="color" value="#e29578" />
    </oc-selection-tile-v2>
  </fieldset>
  <br />
  <h2>Variant Image</h2>
  <fieldset class="demo-multi-selection" aria-label="Select the color of the sneaker">
    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
    >
      <input
        type="checkbox"
        aria-label="White sneaker with three blue stripes"
        name="sneaker"
        value="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
    >
      <input
        type="checkbox"
        aria-label="Dark green sneaker with three white stripes"
        name="sneaker"
        value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
        checked
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
    >
      <input
        type="checkbox"
        aria-label="Dark red sneaker with three white stripes"
        name="sneaker"
        value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2
      variant="image"
      img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
    >
      <input
        type="checkbox"
        aria-label="Dark blue and black sneaker with three white stripes"
        name="sneaker"
        value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
      />
    </oc-selection-tile-v2>
  </fieldset>

  <br />
  <h2>Variant Container</h2>
  <h3>Fit Content</h3>
  <fieldset class="demo-multi-selection" aria-label="Select the color of the longsleeve">
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random1" />
      <img
        slot="content"
        alt="shirt1"
        src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random2" checked />
      <img
        slot="content"
        alt="shirt1"
        src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random3" />
      <img
        slot="content"
        alt="shirt1"
        src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random4" />
      <img
        slot="content"
        alt="shirt1"
        src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
        style="display: block;"
      />
    </oc-selection-tile-v2>
  </fieldset>
  <h3>Custom Width</h3>
  <fieldset class="demo-multi-selection" aria-label="Select random content">
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random1" />
      <div
        slot="content"
        style="display:flex;flex-direction: column; gap: 8px; padding: 16px;"
      >
        <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
          <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
          <span class="oc-copy-125"> Some custom content </span>
        </div>
        <span class="oc-copy-50 oc-text-color-secondary" style="padding-left: 35px;  ">
          Additional information
        </span>
      </div>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random2" checked />
      <div
        slot="content"
        style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
      >
        <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
        <span class="oc-copy-125">Other custom content</span>
      </div>
    </oc-selection-tile-v2>
    <oc-selection-tile-v2 variant="container">
      <input type="checkbox" aria-label="oc-auto" name="service" value="random3" />
      <div
        slot="content"
        style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
      >
        <span class="oc-copy-125">More content</span>
      </div>
    </oc-selection-tile-v2>
  </fieldset>
</div>

<style>
  .demo-multi-selection-group {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .demo-multi-selection {
    display: flex;
    gap: 8px;
    align-items: start;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: multi selection",
  render() {
    return html`
      <div class="demo-multi-selection-group">
        <h2>Variant Text</h2>
        <fieldset class="demo-multi-selection" aria-label="Select a size">
          <oc-selection-tile-v2>
            <input type="checkbox" aria-label="S" name="size" value="S" />
            <label slot="content">S</label>
          </oc-selection-tile-v2>
          <oc-selection-tile-v2>
            <input type="checkbox" aria-label="M" name="size" value="M" checked />
            <label slot="content">M</label>
          </oc-selection-tile-v2>
          <oc-selection-tile-v2>
            <input type="checkbox" aria-label="L" name="size" value="L" />
            <label slot="content">L</label>
          </oc-selection-tile-v2>
          <oc-selection-tile-v2>
            <input type="checkbox" aria-label="XL" name="size" value="XL" />
            <label slot="content">XL</label>
          </oc-selection-tile-v2>
          <oc-selection-tile-v2>
            <input type="checkbox" aria-label="XXL" name="size" value="XXL" />
            <label slot="content">XXL</label>
          </oc-selection-tile-v2>
        </fieldset>
        <br />
        <h2>Variant Color</h2>
        <fieldset class="demo-multi-selection" aria-label="Select a color">
          <oc-selection-tile-v2 variant="color" color="#006d77">
            <input type="checkbox" aria-label="ocean blue" name="color" value="#006d77" />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="color" color="#83c5be">
            <input type="checkbox" aria-label="soft green" name="color" value="#83c5be" checked />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="color" color="#edf6f9">
            <input type="checkbox" aria-label="light blue" name="color" value="#edf6f9" />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="color" color="#ffddd2">
            <input type="checkbox" aria-label="peachy pink" name="color" value="#ffddd2" />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="color" color="#e29578">
            <input type="checkbox" aria-label="warm brown" name="color" value="#e29578" />
          </oc-selection-tile-v2>
        </fieldset>
        <br />
        <h2>Variant Image</h2>
        <fieldset class="demo-multi-selection" aria-label="Select the color of the sneaker">
          <oc-selection-tile-v2
            variant="image"
            img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
          >
            <input
              type="checkbox"
              aria-label="White sneaker with three blue stripes"
              name="sneaker"
              value="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
            />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2
            variant="image"
            img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
          >
            <input
              type="checkbox"
              aria-label="Dark green sneaker with three white stripes"
              name="sneaker"
              value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
              checked
            />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2
            variant="image"
            img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
          >
            <input
              type="checkbox"
              aria-label="Dark red sneaker with three white stripes"
              name="sneaker"
              value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
            />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2
            variant="image"
            img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
          >
            <input
              type="checkbox"
              aria-label="Dark blue and black sneaker with three white stripes"
              name="sneaker"
              value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
            />
          </oc-selection-tile-v2>
        </fieldset>

        <br />
        <h2>Variant Container</h2>
        <h3>Fit Content</h3>
        <fieldset class="demo-multi-selection" aria-label="Select the color of the longsleeve">
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random1" />
            <img
              slot="content"
              alt="shirt1"
              src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random2" checked />
            <img
              slot="content"
              alt="shirt1"
              src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random3" />
            <img
              slot="content"
              alt="shirt1"
              src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random4" />
            <img
              slot="content"
              alt="shirt1"
              src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </oc-selection-tile-v2>
        </fieldset>
        <h3>Custom Width</h3>
        <fieldset class="demo-multi-selection" aria-label="Select random content">
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random1" />
            <div
              slot="content"
              style="display:flex;flex-direction: column; gap: 8px; padding: 16px;"
            >
              <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
                <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
                <span class="oc-copy-125"> Some custom content </span>
              </div>
              <span class="oc-copy-50 oc-text-color-secondary" style="padding-left: 35px;  ">
                Additional information
              </span>
            </div>
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random2" checked />
            <div
              slot="content"
              style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
            >
              <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
              <span class="oc-copy-125">Other custom content</span>
            </div>
          </oc-selection-tile-v2>
          <oc-selection-tile-v2 variant="container">
            <input type="checkbox" aria-label="oc-auto" name="service" value="random3" />
            <div
              slot="content"
              style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
            >
              <span class="oc-copy-125">More content</span>
            </div>
          </oc-selection-tile-v2>
        </fieldset>
      </div>

      <style>
        .demo-multi-selection-group {
          display: flex;
          flex-direction: column;
          gap: 10px;
        }

        .demo-multi-selection {
          display: flex;
          gap: 8px;
          align-items: start;
        }
      </style>
    `;
  }
}

Demo: fit content

Story: components-selection-tile-variations--demo-fit-content · tags: components

A demo showcasing how selection tiles naturally fit their content in a flex layout. The tiles automatically wrap to new lines and adjust their size based on content. This is the default behavior when width-behavior is set to fit-content or not specified. Useful for dynamic content where tile sizes may vary.

<!-- Wrapper to provide a fixed-width parent.-->
<div class="demo-fit-content">
  <!-- Selection tiles with multi-selection behavior.-->
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="36" name="size" value="36" />
    <label slot="content">36</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="37" name="size" value="37" checked />
    <label slot="content">37</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="38" name="size" value="38" />
    <label slot="content">38</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="39" name="size" value="39" />
    <label slot="content">39</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="40" name="size" value="40" />
    <label slot="content">40</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="41" name="size" value="41" />
    <label slot="content">41</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="42" name="size" value="42" />
    <label slot="content">42</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="43" name="size" value="43" />
    <label slot="content">43</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="44" name="size" value="44" />
    <label slot="content">44</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="9 1/2" name="size" value="9 1/2" disabled />
    <label slot="content">9 1/2</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="10" name="size" value="10" />
    <label slot="content">10</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="10 1/2" name="size" value="10 1/2" disabled />
    <label slot="content">10 1/2</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2>
    <input type="checkbox" aria-label="11" name="size" value="11" />
    <label slot="content">11</label>
  </oc-selection-tile-v2>
</div>

<style>
  .demo-fit-content {
    display: flex;
    gap: 5px;
    width: 435px;
    flex-wrap: wrap;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: fit content",
  render() {
    return html` <!-- Wrapper to provide a fixed-width parent.-->
      <div class="demo-fit-content">
        <!-- Selection tiles with multi-selection behavior.-->
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="36" name="size" value="36" />
          <label slot="content">36</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="37" name="size" value="37" checked />
          <label slot="content">37</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="38" name="size" value="38" />
          <label slot="content">38</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="39" name="size" value="39" />
          <label slot="content">39</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="40" name="size" value="40" />
          <label slot="content">40</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="41" name="size" value="41" />
          <label slot="content">41</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="42" name="size" value="42" />
          <label slot="content">42</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="43" name="size" value="43" />
          <label slot="content">43</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="44" name="size" value="44" />
          <label slot="content">44</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="9 1/2" name="size" value="9 1/2" disabled />
          <label slot="content">9 1/2</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="10" name="size" value="10" />
          <label slot="content">10</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="10 1/2" name="size" value="10 1/2" disabled />
          <label slot="content">10 1/2</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2>
          <input type="checkbox" aria-label="11" name="size" value="11" />
          <label slot="content">11</label>
        </oc-selection-tile-v2>
      </div>

      <style>
        .demo-fit-content {
          display: flex;
          gap: 5px;
          width: 435px;
          flex-wrap: wrap;
        }
      </style>`;
  }
}

Demo: fill-parent

Story: components-selection-tile-variations--demo-fill-parent · tags: components

A demo showcasing the width-behavior attribute in a grid layout. When width-behavior is set to fill, selection tiles expand to fill the available space of their parent container. This creates a uniform grid appearance regardless of content length. Ideal for structured layouts where consistent tile sizes are important.

<!-- Wrapper to provide a grid layout.-->
<div class="demo-fill-parent">
  <!-- Selection tiles with fill-parent behavior.-->
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="36" name="size" value="36" />
    <label slot="content">36</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="37" name="size" value="37" checked />
    <label slot="content">37</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="38" name="size" value="38" />
    <label slot="content">38</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="39" name="size" value="39" />
    <label slot="content">39</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="40" name="size" value="40" />
    <label slot="content">40</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="41" name="size" value="41" />
    <label slot="content">41</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="42" name="size" value="42" />
    <label slot="content">42</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="43" name="size" value="43" />
    <label slot="content">43</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="44" name="size" value="44" />
    <label slot="content">44</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="9 1/2" name="size" value="9 1/2" />
    <label slot="content">9 1/2</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="10" name="size" value="10" />
    <label slot="content">10</label>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 width-behavior="fill">
    <input type="checkbox" aria-label="11" name="size" value="11" />
    <label slot="content">11</label>
  </oc-selection-tile-v2>
</div>

<style>
  .demo-fill-parent {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: auto;
    column-gap: 10px;
    row-gap: 15px;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: fill-parent",
  render() {
    return html` <!-- Wrapper to provide a grid layout.-->
      <div class="demo-fill-parent">
        <!-- Selection tiles with fill-parent behavior.-->
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="36" name="size" value="36" />
          <label slot="content">36</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="37" name="size" value="37" checked />
          <label slot="content">37</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="38" name="size" value="38" />
          <label slot="content">38</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="39" name="size" value="39" />
          <label slot="content">39</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="40" name="size" value="40" />
          <label slot="content">40</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="41" name="size" value="41" />
          <label slot="content">41</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="42" name="size" value="42" />
          <label slot="content">42</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="43" name="size" value="43" />
          <label slot="content">43</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="44" name="size" value="44" />
          <label slot="content">44</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="9 1/2" name="size" value="9 1/2" />
          <label slot="content">9 1/2</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="10" name="size" value="10" />
          <label slot="content">10</label>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 width-behavior="fill">
          <input type="checkbox" aria-label="11" name="size" value="11" />
          <label slot="content">11</label>
        </oc-selection-tile-v2>
      </div>

      <style>
        .demo-fill-parent {
          display: grid;
          grid-template-columns: 100px 100px 100px;
          grid-template-rows: auto;
          column-gap: 10px;
          row-gap: 15px;
        }
      </style>`;
  }
}

Demo: selection signifiers

Story: components-selection-tile-variations--demo-selection-signifiers · tags: components

A demo showcasing automatic state synchronization with the oc-selection-signifier-v1 component. The selection tile automatically communicates its state (checked, disabled, hover) to nested selection signifier components. This provides visual indicators for both checkbox and radio button selection types. Demonstrates how the component handles different states: unchecked, checked, and disabled variations.

<style>
  .selection-tile {
    width: 328px;
  }

  .wrapper {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
  }

  .headline-wrapper {
    display: flex;
    gap: 16px;
  }

  div {
    text-align: left;
  }
</style>

<span>
  This demo showcases the automatic way of reflecting the selection tile's states onto the
  selection signifier that is done by the component itself.
</span>

<div class="wrapper">
  <!-- Checkbox -->
  <oc-selection-tile-v2 class="selection-tile" variant="text">
    <input type="checkbox" aria-label="Headline" />
    <div slot="content" class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div slot="content">
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v2>

  <!-- Radio -->
  <oc-selection-tile-v2 class="selection-tile" variant="text">
    <input type="radio" aria-label="Headline" />
    <div slot="content" class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div slot="content">
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v2>

  <!-- Checkbox checked disabled -->
  <oc-selection-tile-v2 class="selection-tile" variant="text">
    <input type="checkbox" aria-label="Headline" checked disabled />
    <div slot="content" class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div slot="content">
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v2>

  <!-- Radio checked disabled -->
  <oc-selection-tile-v2 class="selection-tile" variant="text">
    <input type="radio" aria-label="Headline" checked disabled />
    <div slot="content" class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div slot="content">
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v2>

  <!-- Checkbox disabled -->
  <oc-selection-tile-v2 class="selection-tile" variant="text">
    <input type="checkbox" aria-label="Headline" disabled />
    <div slot="content" class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div slot="content">
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v2>

  <!-- Radio disabled -->
  <oc-selection-tile-v2 class="selection-tile" variant="text">
    <input type="radio" aria-label="Headline" disabled />
    <div slot="content" class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div slot="content">
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v2>
</div>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: selection signifiers",
  render() {
    return html`
      <style>
        .selection-tile {
          width: 328px;
        }

        .wrapper {
          display: flex;
          gap: 16px;
          flex-wrap: wrap;
        }

        .headline-wrapper {
          display: flex;
          gap: 16px;
        }

        div {
          text-align: left;
        }
      </style>

      <span>
        This demo showcases the automatic way of reflecting the selection tile's states onto the
        selection signifier that is done by the component itself.
      </span>

      <div class="wrapper">
        <!-- Checkbox -->
        <oc-selection-tile-v2 class="selection-tile" variant="text">
          <input type="checkbox" aria-label="Headline" />
          <div slot="content" class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div slot="content">
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v2>

        <!-- Radio -->
        <oc-selection-tile-v2 class="selection-tile" variant="text">
          <input type="radio" aria-label="Headline" />
          <div slot="content" class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div slot="content">
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v2>

        <!-- Checkbox checked disabled -->
        <oc-selection-tile-v2 class="selection-tile" variant="text">
          <input type="checkbox" aria-label="Headline" checked disabled />
          <div slot="content" class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div slot="content">
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v2>

        <!-- Radio checked disabled -->
        <oc-selection-tile-v2 class="selection-tile" variant="text">
          <input type="radio" aria-label="Headline" checked disabled />
          <div slot="content" class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div slot="content">
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v2>

        <!-- Checkbox disabled -->
        <oc-selection-tile-v2 class="selection-tile" variant="text">
          <input type="checkbox" aria-label="Headline" disabled />
          <div slot="content" class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div slot="content">
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v2>

        <!-- Radio disabled -->
        <oc-selection-tile-v2 class="selection-tile" variant="text">
          <input type="radio" aria-label="Headline" disabled />
          <div slot="content" class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div slot="content">
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v2>
      </div>
    `;
  }
}

Demo: payment options

Story: components-selection-tile-variations--demo-payment · tags: components

<div class="demo-payment-options" role="radiogroup" aria-label="Zahlart auswählen">
  <oc-selection-tile-v2 variant="container" width-behavior="fill">
    <input
      type="radio"
      name="payment"
      value="direct-debit"
      aria-labelledby="direct-debit-label"
      aria-description="direct-debit-desc"
      checked
    />
    <div slot="content" class="oc-px-100 oc-py-75">
      <div class="demo-payment-option-head" id="direct-debit-label" aria-hidden="true">
        <oc-selection-signifier-v1></oc-selection-signifier-v1>
        Lastschrift
      </div>
      <div class="oc-text-color-secondary" id="direct-debit-desc" aria-hidden="true">
        Die Raten werden monatlich abgebucht.
      </div>
      <oc-divider-v1 class="oc-py-100"></oc-divider-v1>
      <oc-media-object-card-v2
        icon="bank-details"
        size="100"
        variant="icon"
        elevation-level="stacked"
        class="oc-secondary-action"
      >
        <a href="#" aria-label="oc-auto"></a>
        <div slot="headline">IBAN</div>
        <div slot="subline">****1234</div>
        <oc-action-signifier-v1
          slot="action-signifier"
          variant="text"
          label="Ändern"
        ></oc-action-signifier-v1>
      </oc-media-object-card-v2>
    </div>
  </oc-selection-tile-v2>
  <oc-selection-tile-v2 variant="container" width-behavior="fill">
    <input type="radio" name="payment" value="bank-transfer" aria-label="oc-auto" />
    <div slot="content" class="oc-px-100 oc-py-75">
      <div class="demo-payment-option-head">
        <oc-selection-signifier-v1></oc-selection-signifier-v1>
        Überweiseung
      </div>
      <div class="oc-text-color-secondary">Überweise die Raten monatlich selbst.</div>
    </div>
  </oc-selection-tile-v2>
</div>

<style>
  .demo-payment-options {
    display: flex;
    flex-direction: column;
    gap: var(--oc-semantic-spacing-100);
    width: 400px;
  }

  .demo-payment-options > oc-selection-tile-v2::part(default) {
    display: flex;
    flex-direction: column;
    gap: var(--oc-semantic-spacing-50);
  }

  .demo-payment-option-head {
    display: flex;
    gap: var(--oc-semantic-spacing-100);
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: payment options",
  render() {
    return html`
      <div class="demo-payment-options" role="radiogroup" aria-label="Zahlart auswählen">
        <oc-selection-tile-v2 variant="container" width-behavior="fill">
          <input
            type="radio"
            name="payment"
            value="direct-debit"
            aria-labelledby="direct-debit-label"
            aria-description="direct-debit-desc"
            checked
          />
          <div slot="content" class="oc-px-100 oc-py-75">
            <div class="demo-payment-option-head" id="direct-debit-label" aria-hidden="true">
              <oc-selection-signifier-v1></oc-selection-signifier-v1>
              Lastschrift
            </div>
            <div class="oc-text-color-secondary" id="direct-debit-desc" aria-hidden="true">
              Die Raten werden monatlich abgebucht.
            </div>
            <oc-divider-v1 class="oc-py-100"></oc-divider-v1>
            <oc-media-object-card-v2
              icon="bank-details"
              size="100"
              variant="icon"
              elevation-level="stacked"
              class="oc-secondary-action"
            >
              <a href="#" aria-label="oc-auto"></a>
              <div slot="headline">IBAN</div>
              <div slot="subline">****1234</div>
              <oc-action-signifier-v1
                slot="action-signifier"
                variant="text"
                label="Ändern"
              ></oc-action-signifier-v1>
            </oc-media-object-card-v2>
          </div>
        </oc-selection-tile-v2>
        <oc-selection-tile-v2 variant="container" width-behavior="fill">
          <input type="radio" name="payment" value="bank-transfer" aria-label="oc-auto" />
          <div slot="content" class="oc-px-100 oc-py-75">
            <div class="demo-payment-option-head">
              <oc-selection-signifier-v1></oc-selection-signifier-v1>
              Überweiseung
            </div>
            <div class="oc-text-color-secondary">Überweise die Raten monatlich selbst.</div>
          </div>
        </oc-selection-tile-v2>
      </div>

      <style>
        .demo-payment-options {
          display: flex;
          flex-direction: column;
          gap: var(--oc-semantic-spacing-100);
          width: 400px;
        }

        .demo-payment-options > oc-selection-tile-v2::part(default) {
          display: flex;
          flex-direction: column;
          gap: var(--oc-semantic-spacing-50);
        }

        .demo-payment-option-head {
          display: flex;
          gap: var(--oc-semantic-spacing-100);
        }
      </style>
    `;
  }
}

Interaction tests (SelectionTileV2.interactions.stories.ts)

Interaction test stories (automated tests, not usage patterns).

Should Handle Single Selection

Story: components-selection-tile-interaction-tests--should-handle-single-selection · tags: play-fn

Tests single-selection behavior using radio buttons. Verifies that:

  • Only one radio button can be selected per group (based on matching name attributes)
  • Selecting a new option deselects the previously selected option within the same group
  • Multiple independent groups can each have one selected option
<oc-selection-tile-v2>
  <input type="radio" aria-label="oc-auto" name="brand" value="Samsung" />
  <label slot="content">Samsung</label>
</oc-selection-tile-v2>
<oc-selection-tile-v2>
  <input type="radio" aria-label="oc-auto" name="brand" value="LG" />
  <label slot="content">LG</label>
</oc-selection-tile-v2>
<oc-selection-tile-v2>
  <input type="radio" aria-label="oc-auto" name="size" value="XL" />
  <label slot="content">XL</label>
</oc-selection-tile-v2>
<oc-selection-tile-v2>
  <input type="radio" aria-label="oc-auto" name="size" value="XXL" />
  <label slot="content">XXL</label>
</oc-selection-tile-v2>
Story source (TypeScript, verbatim from Storybook)
{
  parameters: {
    docs: {
      disable: true
    }
  },
  render() {
    return html`
      <oc-selection-tile-v2>
        <input type="radio" aria-label="oc-auto" name="brand" value="Samsung" />
        <label slot="content">Samsung</label>
      </oc-selection-tile-v2>
      <oc-selection-tile-v2>
        <input type="radio" aria-label="oc-auto" name="brand" value="LG" />
        <label slot="content">LG</label>
      </oc-selection-tile-v2>
      <oc-selection-tile-v2>
        <input type="radio" aria-label="oc-auto" name="size" value="XL" />
        <label slot="content">XL</label>
      </oc-selection-tile-v2>
      <oc-selection-tile-v2>
        <input type="radio" aria-label="oc-auto" name="size" value="XXL" />
        <label slot="content">XXL</label>
      </oc-selection-tile-v2>
    `;
  },
  async play({
    canvasElement
  }) {
    const [brand1, brand2, size1, size2] = Array.from(canvasElement.getElementsByTagName("oc-selection-tile-v2"));
    const getInput = (element: Element) => element.querySelector("input") as HTMLInputElement;
    await expect(getInput(brand1).checked).toBeFalsy();
    await expect(getInput(brand2).checked).toBeFalsy();
    await expect(getInput(size1).checked).toBeFalsy();
    await expect(getInput(size2).checked).toBeFalsy();
    await click(getInput(brand1));
    await click(getInput(size1));
    await expect(getInput(brand1).checked).toBeTruthy();
    await expect(getInput(brand2).checked).toBeFalsy();
    await expect(getInput(size1).checked).toBeTruthy();
    await expect(getInput(size2).checked).toBeFalsy();
    await click(getInput(brand2));
    await click(getInput(size2));
    await expect(getInput(brand1).checked).toBeFalsy();
    await expect(getInput(brand2).checked).toBeTruthy();
    await expect(getInput(size1).checked).toBeFalsy();
    await expect(getInput(size2).checked).toBeTruthy();
  }
}

Should Handle Multi Selection

Story: components-selection-tile-interaction-tests--should-handle-multi-selection · tags: play-fn

Tests multi-selection behavior using checkboxes. Verifies that:

  • Multiple checkboxes can be selected simultaneously within the same group
  • Selecting additional options does not deselect previously selected options
  • Each checkbox maintains its own independent state
<oc-selection-tile-v2>
  <input type="checkbox" aria-label="oc-auto" name="brand" value="Samsung" />
  <label slot="content">Samsung</label>
</oc-selection-tile-v2>
<oc-selection-tile-v2>
  <input type="checkbox" aria-label="oc-auto" name="brand" value="LG" />
  <label slot="content">LG</label>
</oc-selection-tile-v2>
<oc-selection-tile-v2>
  <input type="checkbox" aria-label="oc-auto" name="size" value="XL" />
  <label slot="content">XL</label>
</oc-selection-tile-v2>
<oc-selection-tile-v2>
  <input type="checkbox" aria-label="oc-auto" name="size" value="XXL" />
  <label slot="content">XXL</label>
</oc-selection-tile-v2>
Story source (TypeScript, verbatim from Storybook)
{
  parameters: {
    docs: {
      disable: true
    }
  },
  render() {
    return html`
      <oc-selection-tile-v2>
        <input type="checkbox" aria-label="oc-auto" name="brand" value="Samsung" />
        <label slot="content">Samsung</label>
      </oc-selection-tile-v2>
      <oc-selection-tile-v2>
        <input type="checkbox" aria-label="oc-auto" name="brand" value="LG" />
        <label slot="content">LG</label>
      </oc-selection-tile-v2>
      <oc-selection-tile-v2>
        <input type="checkbox" aria-label="oc-auto" name="size" value="XL" />
        <label slot="content">XL</label>
      </oc-selection-tile-v2>
      <oc-selection-tile-v2>
        <input type="checkbox" aria-label="oc-auto" name="size" value="XXL" />
        <label slot="content">XXL</label>
      </oc-selection-tile-v2>
    `;
  },
  async play({
    canvasElement
  }) {
    const [brand1, brand2, size1, size2] = Array.from(canvasElement.getElementsByTagName("oc-selection-tile-v2"));
    const getInput = (element: Element) => element.querySelector("input") as HTMLInputElement;
    await expect(getInput(brand1).checked).toBeFalsy();
    await expect(getInput(brand2).checked).toBeFalsy();
    await expect(getInput(size1).checked).toBeFalsy();
    await expect(getInput(size2).checked).toBeFalsy();
    await click(getInput(brand1));
    await click(getInput(size1));
    await expect(getInput(brand1).checked).toBeTruthy();
    await expect(getInput(brand2).checked).toBeFalsy();
    await expect(getInput(size1).checked).toBeTruthy();
    await expect(getInput(size2).checked).toBeFalsy();
    await click(getInput(brand2));
    await click(getInput(size2));
    await expect(getInput(brand1).checked).toBeTruthy();
    await expect(getInput(brand2).checked).toBeTruthy();
    await expect(getInput(size1).checked).toBeTruthy();
    await expect(getInput(size2).checked).toBeTruthy();
  }
}

Should Have Pointer Events Set

Story: components-selection-tile-interaction-tests--should-have-pointer-events-set · tags:

V1 (v1, deprecated, not for generation)

Source: ./src/components/selection-tile/v1/Overview.mdx

Selection tile v1

Important

This is a deprecated version of the selection tile component. For the latest version, see the updated component documentation. Refer to this migration guide to update your project to the latest version.

The selection tile component provides an interactive tile with properties for setting the variant, disabled state, initial checked state, and form identification and processing values. It supports both single and multi-selection behaviors, acting as a radio button for single selections and a checkbox for multiple selections.

Default variation

Story Default:

<oc-selection-tile-v1 variant="text" name="myName">Some Label</oc-selection-tile-v1>

Configuration

The selection tile component offers a variety of styling variants such as color, container, image, and text. This component is configurable, allowing you to tailor its features and appearance to your specific needs. To explore all the available options and adjust the component, use the component configurator and see the changes affect the component in real-time.

Usage guidelines

Before integrating the selection tile component into your project, make sure you have correctly installed the OTTO components package. Look through the variations page for examples of possible component variations. Here, you can discover both common and specific variations that address different use cases.

Info

See the Selection tile UX documentation for detailed user experience guidelines.

Layout considerations

Visual Overflow:

This component has visual overflow. It extends beyond its bounding box and is clipped by parent containers with overflow: hidden. Ensure the parent container has sufficient padding to accommodate the component's full visual area.

Extended Hitbox:

This component has an extended hitbox. The touch area extends beyond its bounding box, so it may be activated when the user clicks or taps outside the visible component area. Ensure sufficient margin around the component to prevent unintended interactions with adjacent elements.

Accessibility

The selection tile component comes with a set of built-in accessibility features to ensure a seamless experience for all users.

Important

If the selection tile component is used in a form, pressing Enter while focused on the selection tile triggers the submit action immediately (implicit submit) if an oc-button component or a normal HTML button with the type submit is also present in the form.

Use oc-aria-label

To make the selection tile recognizable for screen readers, use the default slot to provide a clear and descriptive label. Use the oc-aria-label attribute to provide a clear and descriptive label when the component does not have a visible label (e.g., for variants other than text or container). See the general accessibility documentation for guidance on using oc-aria-label, including how it works with link and masked link behavior.

Further reading

V1/Configuration (v1, deprecated, not for generation)

Source: ./src/components/selection-tile/v1/Configuration.mdx

Selection tile configuration

Configure the selection tile component with the controls below and see the changes live in the preview canvas. Click the Show code button within the preview canvas to see the source code for the current component configuration.

Story Default:

<oc-selection-tile-v1 variant="text" name="myName">Some Label</oc-selection-tile-v1>

Interactive configurator (Storybook controls); every option is listed in the API section of this file.

V1/Interaction tests (SelectionTileV1.interactions.stories.ts)

Interaction test stories (automated tests, not usage patterns).

Should Handle Single Selection

Story: components-selection-tile-v1-interaction-tests--should-handle-single-selection · tags: play-fn

<oc-selection-tile-v1 single-selection name="brand" value="Samsung"
  >Samsung
</oc-selection-tile-v1>
<oc-selection-tile-v1 single-selection name="brand" value="LG">LG</oc-selection-tile-v1>
<oc-selection-tile-v1 single-selection name="size" value="XL">XL</oc-selection-tile-v1>
<oc-selection-tile-v1 single-selection name="size" value="XXL">XXL</oc-selection-tile-v1>
Story source (TypeScript, verbatim from Storybook)
{
  render() {
    return html` <oc-selection-tile-v1 single-selection name="brand" value="Samsung"
        >Samsung
      </oc-selection-tile-v1>
      <oc-selection-tile-v1 single-selection name="brand" value="LG">LG</oc-selection-tile-v1>
      <oc-selection-tile-v1 single-selection name="size" value="XL">XL</oc-selection-tile-v1>
      <oc-selection-tile-v1 single-selection name="size" value="XXL">XXL</oc-selection-tile-v1>`;
  },
  async play({
    canvasElement
  }) {
    const [brand1, brand2, size1, size2] = Array.from(canvasElement.getElementsByTagName("oc-selection-tile-v1"));
    await expect(brand1.checked).toBeFalsy();
    await expect(brand2.checked).toBeFalsy();
    await expect(size1.checked).toBeFalsy();
    await expect(size2.checked).toBeFalsy();
    await click(deepQuerySelector(brand1, ".selection-tile")!);
    await click(deepQuerySelector(size1, ".selection-tile")!);
    await expect(brand1.checked).toBeTruthy();
    await expect(brand2.checked).toBeFalsy();
    await expect(size1.checked).toBeTruthy();
    await expect(size2.checked).toBeFalsy();
    await click(deepQuerySelector(brand2, ".selection-tile")!);
    await click(deepQuerySelector(size2, ".selection-tile")!);
    await expect(brand1.checked).toBeFalsy();
    await expect(brand2.checked).toBeTruthy();
    await expect(size1.checked).toBeFalsy();
    await expect(size2.checked).toBeTruthy();
  }
}

Should Handle Multi Selection

Story: components-selection-tile-v1-interaction-tests--should-handle-multi-selection · tags: play-fn

<oc-selection-tile-v1 name="brand" value="Samsung">Samsung</oc-selection-tile-v1>
<oc-selection-tile-v1 name="brand" value="LG">LG</oc-selection-tile-v1>
<oc-selection-tile-v1 name="size" value="XL">XL</oc-selection-tile-v1>
<oc-selection-tile-v1 name="size" value="XXL">XXL</oc-selection-tile-v1>
Story source (TypeScript, verbatim from Storybook)
{
  render() {
    return html` <oc-selection-tile-v1 name="brand" value="Samsung">Samsung</oc-selection-tile-v1>
      <oc-selection-tile-v1 name="brand" value="LG">LG</oc-selection-tile-v1>
      <oc-selection-tile-v1 name="size" value="XL">XL</oc-selection-tile-v1>
      <oc-selection-tile-v1 name="size" value="XXL">XXL</oc-selection-tile-v1>`;
  },
  async play({
    canvasElement
  }) {
    const [brand1, brand2, size1, size2] = Array.from(canvasElement.getElementsByTagName("oc-selection-tile-v1"));
    await expect(brand1.checked).toBeFalsy();
    await expect(brand2.checked).toBeFalsy();
    await expect(size1.checked).toBeFalsy();
    await expect(size2.checked).toBeFalsy();
    await click(deepQuerySelector(brand1, ".selection-tile")!);
    await click(deepQuerySelector(size1, ".selection-tile")!);
    await expect(brand1.checked).toBeTruthy();
    await expect(brand2.checked).toBeFalsy();
    await expect(size1.checked).toBeTruthy();
    await expect(size2.checked).toBeFalsy();
    await click(deepQuerySelector(brand2, ".selection-tile")!);
    await click(deepQuerySelector(size2, ".selection-tile")!);
    await expect(brand1.checked).toBeTruthy();
    await expect(brand2.checked).toBeTruthy();
    await expect(size1.checked).toBeTruthy();
    await expect(size2.checked).toBeTruthy();
  }
}

V1/Variations (v1, deprecated, not for generation)

Source: ./src/components/selection-tile/v1/Variations.mdx

Variations

Listed below are the most common variations of the selection tile component as well as specific component variations for different use cases.

You can explore all available options using the component configurator, adjust the component to your needs, and see the changes live in a preview canvas.

Default

Story: components-selection-tile-v1-variations--default · tags: components

The default configuration uses the text variant to display a text label in the default slot.

Args: defaultSlot=Some Label, variant=text

<oc-selection-tile-v1 variant="text" name="myName">Some Label</oc-selection-tile-v1>

Color

Story: components-selection-tile-v1-variations--color · tags: components

The color variant uses the --color CSS variable to display a colored circle with the given color and the oc-aria-label attribute to provide an accessible label. This variant can not display content in the default slot.

Args: variant=color, --color=#ffddd2, name=peachy pink, value=#ffddd2, oc-aria-label=Example of a selection tile of variant color with a peachy pink color

<oc-selection-tile-v1 variant="color" name="peachy pink" value="#ffddd2" oc-aria-label="Example of a selection tile of variant color with a peachy pink color" style="--color: #ffddd2"></oc-selection-tile-v1>

Color with gradient

Story: components-selection-tile-v1-variations--color-gradient · tags: components

The color variant and its --color CSS variable can also be used to display a css gradient. You can use any valid CSS gradient value for the --color CSS variable. The oc-aria-label attribute provides an accessible label. This variant can not display content in the default slot.

Args: variant=color, name=rainbow gradient, value=colorful, oc-aria-label=Rainbow gradient

<oc-selection-tile-v1 variant="color" name="rainbow gradient" value="colorful" oc-aria-label="Rainbow gradient" style="--color: ${gradient}"
  >${unsafeHTML(defaultSlot)}</oc-selection-tile-v1
>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Color with gradient",
  args: {
    variant: "color",
    name: "rainbow gradient",
    value: "colorful",
    "oc-aria-label": "Rainbow gradient"
  },
  render({
    defaultSlot,
    ...props
  }) {
    return html`<oc-selection-tile-v1 ${spread(props)} style="--color: ${gradient}"
      >${unsafeHTML(defaultSlot)}</oc-selection-tile-v1
    >`;
  }
}

Image

Story: components-selection-tile-v1-variations--image · tags: components

The image variant uses the img-src attribute to display an image and the oc-aria-label attribute to provide an accessible label. This variant can not display content in the default slot.

Args: variant=image, name=sneaker, value=https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png, oc-aria-label=Example of a selection tile of variant image with a placeholder image, img-src=https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png

<oc-selection-tile-v1 variant="image" name="sneaker" value="https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png" oc-aria-label="Example of a selection tile of variant image with a placeholder image" img-src="https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png"></oc-selection-tile-v1>

Strike through

Story: components-selection-tile-v1-variations--strike-through · tags: components

The default variant with the strike-through attribute set to true, showing a diagonal line in the selection tile.

Args: defaultSlot=Label, strike-through=true

<oc-selection-tile-v1 variant="text" name="myName" strike-through>Label</oc-selection-tile-v1>

Strike through color

Story: components-selection-tile-v1-variations--strike-through-color · tags: components

The color variant with the strike-through attribute set to true, showing a diagonal line in the selection tile.

Args: variant=color, strike-through=true, --color=#ffddd2, name=peachy pink, value=#ffddd2, oc-aria-label=Example of a selection tile of variant color with a peachy pink color and a strike-through

<oc-selection-tile-v1 variant="color" name="peachy pink" strike-through value="#ffddd2" oc-aria-label="Example of a selection tile of variant color with a peachy pink color and a strike-through" style="--color: #ffddd2"></oc-selection-tile-v1>

Disabled

Story: components-selection-tile-v1-variations--disabled · tags: components

The text variant with the disabled attribute set to true, preventing the user from interacting with the component.

Args: defaultSlot=Some Label, variant=text, disabled=true

<oc-selection-tile-v1 variant="text" disabled name="myName">Some Label</oc-selection-tile-v1>

Container

Story: components-selection-tile-v1-variations--container · tags: components

The container variant displaying custom content in the default slot that uses a wrapper to have a custom width.

Args: variant=container, name=service, value=random1, oc-aria-label=Example of a container selection tile with custom content, defaultSlot=(see snippet)

<oc-selection-tile-v1 variant="container" name="service" value="random1" oc-aria-label="Example of a container selection tile with custom content">
  <!-- Wrapper for custom width.-->
      <div style="display:flex;flex-direction: column; gap: 8px; padding: 16px;">
      <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
        <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
        <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Some custom content</p>
      </div>
      <!-- Use utility classes instead of inline-style. -->
      <p
        style="font: var(--oc-semantic-font-copy-50); padding-left: 35px; margin: 0; color:  var(--oc-semantic-color-text-secondary)"
      >
        Additional information
      </p>
    </div>
</oc-selection-tile-v1>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Container",
  args: {
    variant: "container",
    name: "service",
    value: "random1",
    "oc-aria-label": "Example of a container selection tile with custom content",
    defaultSlot: `<!-- Wrapper for custom width.-->
    <div style="display:flex;flex-direction: column; gap: 8px; padding: 16px;">
    <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
      <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
      <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Some custom content</p>
    </div>
    <!-- Use utility classes instead of inline-style. -->
    <p
      style="font: var(--oc-semantic-font-copy-50); padding-left: 35px; margin: 0; color:  var(--oc-semantic-color-text-secondary)"
    >
      Additional information
    </p>
  </div>`
  }
}

Container with placeholder

Story: components-selection-tile-v1-variations--container-with-placeholder · tags: components

The container variant displaying the oc-placeholder-v1 component as a placeholder in the default slot.

Args: variant=container, name=service, value=random1, oc-aria-label=Example of a container selection tile with a placeholder element, defaultSlot=(see snippet)

<oc-selection-tile-v1 variant="container" name="service" value="random1" oc-aria-label="Example of a container selection tile with a placeholder element">
  <oc-placeholder-v1 style="display: flex;
      width: 165px;
      height: 80px;
      justify-content: center;
      align-items: center;
      flex-shrink: 0;
      opacity: 0.4;
      border-radius: 8px;
      background: #30D9BA;
      color: #fff;
      font-weight: 700;
      padding: 8px;
      ">PLACEHOLDER</oc-placeholder-v1>
</oc-selection-tile-v1>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Container with placeholder",
  args: {
    variant: "container",
    name: "service",
    value: "random1",
    "oc-aria-label": "Example of a container selection tile with a placeholder element",
    defaultSlot: `<oc-placeholder-v1 style="display: flex;
    width: 165px;
    height: 80px;
    justify-content: center;
    align-items: center;
    flex-shrink: 0;
    opacity: 0.4;
    border-radius: 8px;
    background: #30D9BA;
    color: #fff;
    font-weight: 700;
    padding: 8px;
    ">PLACEHOLDER</oc-placeholder-v1>`
  }
}

Container with image

Story: components-selection-tile-v1-variations--container-with-image · tags: components

The container variant displaying an image in the default slot with custom markup to have a custom width and height.

Args: variant=container, name=service, value=random1, oc-aria-label=Example of a container selection tile with an image, defaultSlot=(see snippet)

<oc-selection-tile-v1 variant="container" name="service" value="random1" oc-aria-label="Example of a container selection tile with an image">
  <div style="overflow: hidden; border-radius: 8px">
      <img
        alt="Placeholder image"
        src="https://www.otto.de/assets-storybook/assets/img-placeholder-100.DVwSxVZf.png"
        style="display: block; width: 64px; height: 80px;"
      />
    </div>
</oc-selection-tile-v1>
Story source (TypeScript, verbatim from Storybook)
{
  name: "Container with image",
  args: {
    variant: "container",
    name: "service",
    value: "random1",
    "oc-aria-label": "Example of a container selection tile with an image",
    defaultSlot: `<div style="overflow: hidden; border-radius: 8px">
    <img
      alt="Placeholder image"
      src="${placeholderImage}"
      style="display: block; width: 64px; height: 80px;"
    />
  </div>`
  }
}

Demo: single-selection

Story: components-selection-tile-v1-variations--demo-single-selection · tags: components

A demo showcasing how each variation of the selection tile can act as a radio button group by using the single-selection and name attributes.

<div class="demo-single-selection-group">
  <h2>Variant Text</h2>
  <div class="demo-single-selection" role="radiogroup" aria-label="Select a size">
    <oc-selection-tile-v1 single-selection name="size" value="S">S</oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection name="size" value="M">M</oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection name="size" value="L">L</oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection name="size" value="XL">XL</oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection name="size" value="XXL">XXL</oc-selection-tile-v1>
  </div>
  <br />
  <h2>Variant Color</h2>
  <div class="demo-single-selection" role="radiogroup" aria-label="Select a color">
    <oc-selection-tile-v1
      single-selection
      name="color"
      variant="color"
      value="#006d77"
      color="#006d77"
      oc-aria-label="ocean blue"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      name="color"
      variant="color"
      value="#83c5be"
      color="#83c5be"
      oc-aria-label="soft green"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      name="color"
      variant="color"
      value="#edf6f9"
      color="#edf6f9"
      oc-aria-label="light blue"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      name="color"
      variant="color"
      value="#ffddd2"
      color="#ffddd2"
      oc-aria-label="peachy pink"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      name="color"
      variant="color"
      value="#e29578"
      color="#e29578"
      oc-aria-label="warm brown"
    ></oc-selection-tile-v1>
  </div>
  <br />
  <h2>Variant Image</h2>
  <div
    class="demo-single-selection"
    role="radiogroup"
    aria-label="Select the color of the sneaker"
  >
    <oc-selection-tile-v1
      single-selection
      variant="image"
      name="sneaker"
      value="	https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
      img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf?w=42&h=42"
      oc-aria-label="White sneaker with three blue stripes"
    >
    </oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
      img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2?w=42&h=42"
      oc-aria-label="Dark green sneaker with three white stripes"
    >
    </oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
      img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae?w=42&h=42"
      oc-aria-label="Dark red sneaker with three white stripes"
    >
    </oc-selection-tile-v1>
    <oc-selection-tile-v1
      single-selection
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
      img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6?w=42&h=42"
      oc-aria-label="Dark blue and black sneaker with three white stripes"
    >
    </oc-selection-tile-v1>
  </div>

  <br />
  <h2>Variant Container</h2>
  <h3>Fit content</h3>
  <div
    class="demo-single-selection"
    role="radiogroup"
    aria-label="Select the color of the longsleeve"
  >
    <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="Orange longsleeve"
          src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="Blue longsleeve"
          src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="Black longsleeve"
          src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="Dark red longsleeve"
          src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
  </div>
  <h3>Custom width</h3>
  <div class="demo-single-selection" role="radiogroup" aria-label="Select random content">
    <oc-selection-tile-v1 single-selection variant="container" name="random" value="random1">
      <div style="display:flex; flex-direction: column; gap: 8px; padding: 16px; width: 100%;">
        <div style="display:flex; flex-direction: row; gap: 12px; align-items:center;">
          <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
          <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Some custom content</p>
        </div>
        <!-- replace inline-style with utility -->
        <p
          style="font: var(--oc-semantic-font-copy-50); padding-left: 35px; margin: 0; color: var(--oc-semantic-color-text-secondary)"
        >
          Additional information
        </p>
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection variant="container" name="random" value="random2">
      <div
        style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
      >
        <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
        <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Other custom content</p>
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 single-selection variant="container" name="random" value="random3">
      <div
        style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
      >
        <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">More content</p>
      </div>
    </oc-selection-tile-v1>
  </div>

  <style>
    .demo-single-selection-group {
      display: flex;
      flex-direction: column;
      gap: 10px;
    }

    .demo-single-selection {
      display: flex;
      gap: 8px;
    }
  </style>
</div>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: single-selection",
  render() {
    return html` <div class="demo-single-selection-group">
      <h2>Variant Text</h2>
      <div class="demo-single-selection" role="radiogroup" aria-label="Select a size">
        <oc-selection-tile-v1 single-selection name="size" value="S">S</oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection name="size" value="M">M</oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection name="size" value="L">L</oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection name="size" value="XL">XL</oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection name="size" value="XXL">XXL</oc-selection-tile-v1>
      </div>
      <br />
      <h2>Variant Color</h2>
      <div class="demo-single-selection" role="radiogroup" aria-label="Select a color">
        <oc-selection-tile-v1
          single-selection
          name="color"
          variant="color"
          value="#006d77"
          color="#006d77"
          oc-aria-label="ocean blue"
        ></oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          name="color"
          variant="color"
          value="#83c5be"
          color="#83c5be"
          oc-aria-label="soft green"
        ></oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          name="color"
          variant="color"
          value="#edf6f9"
          color="#edf6f9"
          oc-aria-label="light blue"
        ></oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          name="color"
          variant="color"
          value="#ffddd2"
          color="#ffddd2"
          oc-aria-label="peachy pink"
        ></oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          name="color"
          variant="color"
          value="#e29578"
          color="#e29578"
          oc-aria-label="warm brown"
        ></oc-selection-tile-v1>
      </div>
      <br />
      <h2>Variant Image</h2>
      <div
        class="demo-single-selection"
        role="radiogroup"
        aria-label="Select the color of the sneaker"
      >
        <oc-selection-tile-v1
          single-selection
          variant="image"
          name="sneaker"
          value="	https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
          img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf?w=42&h=42"
          oc-aria-label="White sneaker with three blue stripes"
        >
        </oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          variant="image"
          name="sneaker"
          value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
          img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2?w=42&h=42"
          oc-aria-label="Dark green sneaker with three white stripes"
        >
        </oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          variant="image"
          name="sneaker"
          value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
          img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae?w=42&h=42"
          oc-aria-label="Dark red sneaker with three white stripes"
        >
        </oc-selection-tile-v1>
        <oc-selection-tile-v1
          single-selection
          variant="image"
          name="sneaker"
          value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
          img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6?w=42&h=42"
          oc-aria-label="Dark blue and black sneaker with three white stripes"
        >
        </oc-selection-tile-v1>
      </div>

      <br />
      <h2>Variant Container</h2>
      <h3>Fit content</h3>
      <div
        class="demo-single-selection"
        role="radiogroup"
        aria-label="Select the color of the longsleeve"
      >
        <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
          <div style="overflow: hidden; border-radius: 8px">
            <img
              alt="Orange longsleeve"
              src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </div>
        </oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
          <div style="overflow: hidden; border-radius: 8px">
            <img
              alt="Blue longsleeve"
              src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </div>
        </oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
          <div style="overflow: hidden; border-radius: 8px">
            <img
              alt="Black longsleeve"
              src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </div>
        </oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection variant="container" name="shirt" value="random1">
          <div style="overflow: hidden; border-radius: 8px">
            <img
              alt="Dark red longsleeve"
              src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
              style="display: block;"
            />
          </div>
        </oc-selection-tile-v1>
      </div>
      <h3>Custom width</h3>
      <div class="demo-single-selection" role="radiogroup" aria-label="Select random content">
        <oc-selection-tile-v1 single-selection variant="container" name="random" value="random1">
          <div style="display:flex; flex-direction: column; gap: 8px; padding: 16px; width: 100%;">
            <div style="display:flex; flex-direction: row; gap: 12px; align-items:center;">
              <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
              <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Some custom content</p>
            </div>
            <!-- replace inline-style with utility -->
            <p
              style="font: var(--oc-semantic-font-copy-50); padding-left: 35px; margin: 0; color: var(--oc-semantic-color-text-secondary)"
            >
              Additional information
            </p>
          </div>
        </oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection variant="container" name="random" value="random2">
          <div
            style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
          >
            <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
            <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Other custom content</p>
          </div>
        </oc-selection-tile-v1>
        <oc-selection-tile-v1 single-selection variant="container" name="random" value="random3">
          <div
            style="display:flex; flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
          >
            <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">More content</p>
          </div>
        </oc-selection-tile-v1>
      </div>

      <style>
        .demo-single-selection-group {
          display: flex;
          flex-direction: column;
          gap: 10px;
        }

        .demo-single-selection {
          display: flex;
          gap: 8px;
        }
      </style>
    </div>`;
  }
}

Demo: multi selection

Story: components-selection-tile-v1-variations--demo-multi-selection · tags: components

A demo showcasing how each variation of the selection tile can act as a checkbox group by using the name attribute.

<div class="demo-multi-selection-group">
  <h2>Variant Text</h2>
  <fieldset class="demo-multi-selection" aria-label="Select a size">
    <oc-selection-tile-v1 name="size" value="S">S</oc-selection-tile-v1>
    <oc-selection-tile-v1 name="size" value="M">M</oc-selection-tile-v1>
    <oc-selection-tile-v1 name="size" value="L">L</oc-selection-tile-v1>
    <oc-selection-tile-v1 name="size" value="XL">XL</oc-selection-tile-v1>
    <oc-selection-tile-v1 name="size" value="XXL">XXL</oc-selection-tile-v1>
  </fieldset>
  <br />
  <h2>Variant Color</h2>
  <fieldset class="demo-multi-selection" aria-label="Select a color">
    <oc-selection-tile-v1
      name="color"
      variant="color"
      value="#006d77"
      color="#006d77"
      oc-aria-label="ocean blue"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      name="color"
      variant="color"
      value="#83c5be"
      color="#83c5be"
      oc-aria-label="soft green"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      name="color"
      variant="color"
      value="#edf6f9"
      color="#edf6f9"
      oc-aria-label="light blue"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      name="color"
      variant="color"
      value="#ffddd2"
      color="#ffddd2"
      oc-aria-label="peachy pink"
    ></oc-selection-tile-v1>
    <oc-selection-tile-v1
      name="color"
      variant="color"
      value="#e29578"
      color="#e29578"
      oc-aria-label="warm brown"
    ></oc-selection-tile-v1>
  </fieldset>
  <br />
  <h2>Variant Image</h2>
  <fieldset class="demo-multi-selection" aria-label="Select the color of the sneaker">
    <oc-selection-tile-v1
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
      img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf?w=42&h=42"
      oc-aria-label="White sneaker with three blue stripes"
    >
    </oc-selection-tile-v1>
    <oc-selection-tile-v1
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
      img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2?w=42&h=42"
      oc-aria-label="Dark green sneaker with three white stripes"
    >
    </oc-selection-tile-v1>
    <oc-selection-tile-v1
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
      img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae?w=42&h=42"
      oc-aria-label="Dark red sneaker with three white stripes"
    >
    </oc-selection-tile-v1>
    <oc-selection-tile-v1
      variant="image"
      name="sneaker"
      value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
      img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6?w=42&h=42"
      oc-aria-label="Dark blue and black sneaker with three white stripes"
    >
    </oc-selection-tile-v1>
  </fieldset>

  <br />
  <h2>Variant Container</h2>
  <h3>Fit Content</h3>
  <fieldset class="demo-multi-selection" aria-label="Select the color of the longsleeve">
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="shirt1"
          src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="shirt1"
          src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="shirt1"
          src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div style="overflow: hidden; border-radius: 8px">
        <img
          alt="shirt1"
          src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
          style="display: block;"
        />
      </div>
    </oc-selection-tile-v1>
  </fieldset>
  <h3>Custom Width</h3>
  <fieldset class="demo-multi-selection" aria-label="Select random content">
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div style="display:flex;flex-direction: column; gap: 8px; padding: 16px;">
        <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
          <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
          <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">
            Some custom content
          </p>
        </div>
        <!-- replace inline-style with utility -->
        <p
          style="font: var(--oc-semantic-font-copy-50); padding-left: 35px; margin: 0; color:  var(--oc-semantic-color-text-secondary)"
        >
          Additional information
        </p>
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div
        style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
      >
        <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
        <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Other custom content</p>
      </div>
    </oc-selection-tile-v1>
    <oc-selection-tile-v1 variant="container" name="service" value="random1">
      <div
        style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
      >
        <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">More content</p>
      </div>
    </oc-selection-tile-v1>
  </fieldset>
</div>

<style lang="scss">
  .demo-multi-selection-group {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }

  .demo-multi-selection {
    display: flex;
    gap: 8px;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: multi selection",
  render() {
    return html`
      <div class="demo-multi-selection-group">
        <h2>Variant Text</h2>
        <fieldset class="demo-multi-selection" aria-label="Select a size">
          <oc-selection-tile-v1 name="size" value="S">S</oc-selection-tile-v1>
          <oc-selection-tile-v1 name="size" value="M">M</oc-selection-tile-v1>
          <oc-selection-tile-v1 name="size" value="L">L</oc-selection-tile-v1>
          <oc-selection-tile-v1 name="size" value="XL">XL</oc-selection-tile-v1>
          <oc-selection-tile-v1 name="size" value="XXL">XXL</oc-selection-tile-v1>
        </fieldset>
        <br />
        <h2>Variant Color</h2>
        <fieldset class="demo-multi-selection" aria-label="Select a color">
          <oc-selection-tile-v1
            name="color"
            variant="color"
            value="#006d77"
            color="#006d77"
            oc-aria-label="ocean blue"
          ></oc-selection-tile-v1>
          <oc-selection-tile-v1
            name="color"
            variant="color"
            value="#83c5be"
            color="#83c5be"
            oc-aria-label="soft green"
          ></oc-selection-tile-v1>
          <oc-selection-tile-v1
            name="color"
            variant="color"
            value="#edf6f9"
            color="#edf6f9"
            oc-aria-label="light blue"
          ></oc-selection-tile-v1>
          <oc-selection-tile-v1
            name="color"
            variant="color"
            value="#ffddd2"
            color="#ffddd2"
            oc-aria-label="peachy pink"
          ></oc-selection-tile-v1>
          <oc-selection-tile-v1
            name="color"
            variant="color"
            value="#e29578"
            color="#e29578"
            oc-aria-label="warm brown"
          ></oc-selection-tile-v1>
        </fieldset>
        <br />
        <h2>Variant Image</h2>
        <fieldset class="demo-multi-selection" aria-label="Select the color of the sneaker">
          <oc-selection-tile-v1
            variant="image"
            name="sneaker"
            value="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf"
            img-src="https://i.otto.de/i/otto/5c89660c-3a39-5bab-9b46-27a9875b42cf?w=42&h=42"
            oc-aria-label="White sneaker with three blue stripes"
          >
          </oc-selection-tile-v1>
          <oc-selection-tile-v1
            variant="image"
            name="sneaker"
            value="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2"
            img-src="https://i.otto.de/i/otto/c4ace723-bb10-55a1-b3ae-b64b58d1a7a2?w=42&h=42"
            oc-aria-label="Dark green sneaker with three white stripes"
          >
          </oc-selection-tile-v1>
          <oc-selection-tile-v1
            variant="image"
            name="sneaker"
            value="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae"
            img-src="https://i.otto.de/i/otto/c44148c1-e7f2-55d9-a253-4c1c8bfb25ae?w=42&h=42"
            oc-aria-label="Dark red sneaker with three white stripes"
          >
          </oc-selection-tile-v1>
          <oc-selection-tile-v1
            variant="image"
            name="sneaker"
            value="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6"
            img-src="https://i.otto.de/i/otto/d6277f92-899b-5b27-8d05-670b539b8dc6?w=42&h=42"
            oc-aria-label="Dark blue and black sneaker with three white stripes"
          >
          </oc-selection-tile-v1>
        </fieldset>

        <br />
        <h2>Variant Container</h2>
        <h3>Fit Content</h3>
        <fieldset class="demo-multi-selection" aria-label="Select the color of the longsleeve">
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div style="overflow: hidden; border-radius: 8px">
              <img
                alt="shirt1"
                src="https://i.otto.de/i/otto/4dc5c767-f806-51a8-aacf-a18b8842f8f4?h=80&w=64&sm=clamp"
                style="display: block;"
              />
            </div>
          </oc-selection-tile-v1>
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div style="overflow: hidden; border-radius: 8px">
              <img
                alt="shirt1"
                src="https://i.otto.de/i/otto/63aa8e88-35de-5e83-968b-c28fb5d8ff4c?h=80&w=64&sm=clamp"
                style="display: block;"
              />
            </div>
          </oc-selection-tile-v1>
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div style="overflow: hidden; border-radius: 8px">
              <img
                alt="shirt1"
                src="https://i.otto.de/i/otto/4d059c4b-c2f1-565a-a7b0-c2b797191eba?h=80&w=64&sm=clamp"
                style="display: block;"
              />
            </div>
          </oc-selection-tile-v1>
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div style="overflow: hidden; border-radius: 8px">
              <img
                alt="shirt1"
                src="https://i.otto.de/i/otto/73dd135c-2e52-580d-8c04-c82e4b374ed3?h=80&w=64&sm=clamp"
                style="display: block;"
              />
            </div>
          </oc-selection-tile-v1>
        </fieldset>
        <h3>Custom Width</h3>
        <fieldset class="demo-multi-selection" aria-label="Select random content">
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div style="display:flex;flex-direction: column; gap: 8px; padding: 16px;">
              <div style="display:flex;flex-direction: row; gap: 12px; align-items:center;">
                <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
                <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">
                  Some custom content
                </p>
              </div>
              <!-- replace inline-style with utility -->
              <p
                style="font: var(--oc-semantic-font-copy-50); padding-left: 35px; margin: 0; color:  var(--oc-semantic-color-text-secondary)"
              >
                Additional information
              </p>
            </div>
          </oc-selection-tile-v1>
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div
              style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px;"
            >
              <oc-icon-v1 type="wishlist" size="100"></oc-icon-v1>
              <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">Other custom content</p>
            </div>
          </oc-selection-tile-v1>
          <oc-selection-tile-v1 variant="container" name="service" value="random1">
            <div
              style="display:flex;flex-direction: row; gap: 12px; align-items:center; padding: 16px; width: 300px;"
            >
              <p style="font: var(--oc-semantic-font-copy-125); margin: 0;">More content</p>
            </div>
          </oc-selection-tile-v1>
        </fieldset>
      </div>

      <style lang="scss">
        .demo-multi-selection-group {
          display: flex;
          flex-direction: column;
          gap: 10px;
        }

        .demo-multi-selection {
          display: flex;
          gap: 8px;
        }
      </style>
    `;
  }
}

Demo: fit content

Story: components-selection-tile-v1-variations--demo-fit-content · tags: components

A demo showcasing how multiple container variants with multi-selection behavior can fit the width of the parent element.

<!-- Wrapper to provide a fixed-width parent.-->
<div class="demo-fit-content">
  <!-- Selection tiles with multi-selection behavior.-->
  <oc-selection-tile-v1 name="size" value="36">36</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="37">37</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="38">38</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="39">39</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="40">40</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="41">41</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="42">42</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="43">43</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="44">44</oc-selection-tile-v1>
  <oc-selection-tile-v1 disabled name="size" value="9 1/2">9 1/2</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="10">10</oc-selection-tile-v1>
  <oc-selection-tile-v1 disabled name="size" value="10 1/2">10 1/2</oc-selection-tile-v1>
  <oc-selection-tile-v1 name="size" value="11">11</oc-selection-tile-v1>
</div>

<style>
  .demo-fit-content {
    display: flex;
    gap: 5px;
    width: 435px;
    flex-wrap: wrap;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: fit content",
  render() {
    return html` <!-- Wrapper to provide a fixed-width parent.-->
      <div class="demo-fit-content">
        <!-- Selection tiles with multi-selection behavior.-->
        <oc-selection-tile-v1 name="size" value="36">36</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="37">37</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="38">38</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="39">39</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="40">40</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="41">41</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="42">42</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="43">43</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="44">44</oc-selection-tile-v1>
        <oc-selection-tile-v1 disabled name="size" value="9 1/2">9 1/2</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="10">10</oc-selection-tile-v1>
        <oc-selection-tile-v1 disabled name="size" value="10 1/2">10 1/2</oc-selection-tile-v1>
        <oc-selection-tile-v1 name="size" value="11">11</oc-selection-tile-v1>
      </div>

      <style>
        .demo-fit-content {
          display: flex;
          gap: 5px;
          width: 435px;
          flex-wrap: wrap;
        }
      </style>`;
  }
}

Demo: fill-parent

Story: components-selection-tile-v1-variations--demo-fill-parent · tags: components

A demo showcasing the fill-parent attribute to set the width of the selection tiles to match the width of the grid columns.

<!-- Wrapper to provide a grid layout.-->
<div class="demo-fill-parent">
  <!-- Selection tiles with fill-parent behavior.-->
  <oc-selection-tile-v1 fill-parent name="size" value="36">36</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="37">37</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="38">38</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="39">39</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="40">40</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="41">41</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="42">42</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="43">43</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="44">44</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="9 1/2">9 1/2"</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="10">10</oc-selection-tile-v1>
  <oc-selection-tile-v1 fill-parent name="size" value="11">11</oc-selection-tile-v1>
</div>

<style>
  .demo-fill-parent {
    display: grid;
    grid-template-columns: 100px 100px 100px;
    grid-template-rows: auto;
    column-gap: 10px;
    row-gap: 15px;
  }
</style>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: fill-parent",
  render() {
    return html` <!-- Wrapper to provide a grid layout.-->
      <div class="demo-fill-parent">
        <!-- Selection tiles with fill-parent behavior.-->
        <oc-selection-tile-v1 fill-parent name="size" value="36">36</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="37">37</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="38">38</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="39">39</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="40">40</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="41">41</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="42">42</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="43">43</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="44">44</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="9 1/2">9 1/2"</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="10">10</oc-selection-tile-v1>
        <oc-selection-tile-v1 fill-parent name="size" value="11">11</oc-selection-tile-v1>
      </div>

      <style>
        .demo-fill-parent {
          display: grid;
          grid-template-columns: 100px 100px 100px;
          grid-template-rows: auto;
          column-gap: 10px;
          row-gap: 15px;
        }
      </style>`;
  }
}

Demo: selection signifiers

Story: components-selection-tile-v1-variations--demo-selection-signifiers · tags: components

<style>
  .selection-tile {
    width: 328px;
  }

  .wrapper {
    display: flex;
    gap: 16px;
    flex-wrap: wrap;
  }

  .headline-wrapper {
    display: flex;
    gap: 16px;
  }

  div {
    text-align: left;
  }
</style>

<p>
  This demo showcases the automatic way of reflecting the selection tile's states onto the
  selection signifier that is done by the component itself.
</p>

<div class="wrapper">
  <!-- Checkbox -->
  <oc-selection-tile-v1 class="selection-tile" variant="text">
    <div class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div>
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v1>

  <!-- Radio -->
  <oc-selection-tile-v1 class="selection-tile" variant="text" single-selection>
    <div class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div>
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v1>

  <!-- Checkbox checked disabled -->
  <oc-selection-tile-v1 class="selection-tile" variant="text" checked disabled>
    <div class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div>
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v1>

  <!-- Radio checked disabled -->
  <oc-selection-tile-v1
    class="selection-tile"
    variant="text"
    single-selection
    checked
    disabled
  >
    <div class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div>
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v1>

  <!-- Checkbox disabled -->
  <oc-selection-tile-v1 class="selection-tile" variant="text" disabled>
    <div class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div>
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v1>

  <!-- Radio disabled -->
  <oc-selection-tile-v1 class="selection-tile" variant="text" single-selection disabled>
    <div class="headline-wrapper">
      <oc-selection-signifier-v1></oc-selection-signifier-v1>
      <div class="oc-copy-100 oc-copy--bold">Headline</div>
    </div>
    <div>
      Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
      tincidunt.
    </div>
  </oc-selection-tile-v1>
</div>
Story source (TypeScript, verbatim from Storybook)
{
  argTypes: hideControlsBadge(Metadata),
  parameters: {
    controls: {
      disabled: true
    }
  },
  name: "Demo: selection signifiers",
  render() {
    return html`
      <style>
        .selection-tile {
          width: 328px;
        }

        .wrapper {
          display: flex;
          gap: 16px;
          flex-wrap: wrap;
        }

        .headline-wrapper {
          display: flex;
          gap: 16px;
        }

        div {
          text-align: left;
        }
      </style>

      <p>
        This demo showcases the automatic way of reflecting the selection tile's states onto the
        selection signifier that is done by the component itself.
      </p>

      <div class="wrapper">
        <!-- Checkbox -->
        <oc-selection-tile-v1 class="selection-tile" variant="text">
          <div class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div>
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v1>

        <!-- Radio -->
        <oc-selection-tile-v1 class="selection-tile" variant="text" single-selection>
          <div class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div>
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v1>

        <!-- Checkbox checked disabled -->
        <oc-selection-tile-v1 class="selection-tile" variant="text" checked disabled>
          <div class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div>
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v1>

        <!-- Radio checked disabled -->
        <oc-selection-tile-v1
          class="selection-tile"
          variant="text"
          single-selection
          checked
          disabled
        >
          <div class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div>
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v1>

        <!-- Checkbox disabled -->
        <oc-selection-tile-v1 class="selection-tile" variant="text" disabled>
          <div class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div>
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v1>

        <!-- Radio disabled -->
        <oc-selection-tile-v1 class="selection-tile" variant="text" single-selection disabled>
          <div class="headline-wrapper">
            <oc-selection-signifier-v1></oc-selection-signifier-v1>
            <div class="oc-copy-100 oc-copy--bold">Headline</div>
          </div>
          <div>
            Lorem ipsum dolor sit amet consectetur. Senectus odio pellentesque eget bibendum viverra
            tincidunt.
          </div>
        </oc-selection-tile-v1>
      </div>
    `;
  }
}