Add component variants to SDC, storybook style

Created on 5 May 2025, 5 days ago

Problem/Motivation

from #3390712-71: Add component variants to SDC

Instead of:

name:  Card
variants:
  primary:
    title: Primary
    description: ...
  secondary:
    title: Secondary
    description: ...
  inverted:
    title: Inverted
    description: ...
  primary:
    title: Primary
    description: ...
props: {}
slots: {}

I propose this schema (similar to what Storybook does):

name:  Card
variants:
  primary:
    title: Primary
    description: ...
    props:
       kind: button
       text: my button
       third_prop: value13

  secondary:
    title: Secondary
    description: ...
    props:
       kind: link
       text: my button
       third_prop: value32
props: {}
slots: {}

Here, variants.<name>.props would be validated against the declared props.*. Then any wrapper (e.g., for Storybook or style guide rendering) can consume and render the SDC component properly — without leaking non-production logic into production code.

And most importantly - do not expose the variant name as a prop to the component's Twig.

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

Introduced terminology

API changes

Data model changes

Release notes snippet

Feature request
Status

Active

Version

11.0 🔥

Component

single-directory components

Created by

🇫🇷France nod_ Lille

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @nod_
  • 🇫🇷France nod_ Lille

    How would it work when you define a value for a prop in a variant, then call the template with a different value for that prop? does the variant setting win over the assigned value? Do we trigger a warning when a prop defined in a variant is assigned when calling a template directly?

  • 🇪🇸Spain penyaskito Seville 💃, Spain 🇪🇸, UTC+2 🇪🇺

    Related to nod_'s question: how would you relate those variants props to data from Drupal, e.g. a value coming from one entity field? Or ar they expected to always be hard-coded values, and "content" data only used in slots?

  • 🇦🇺Australia alex.skrypnyk Melbourne
  • 🇦🇺Australia alex.skrypnyk Melbourne
  • 🇦🇺Australia alex.skrypnyk Melbourne
  • First commit to issue fork.
  • 🇮🇳India supriyagupta

    Add card.imfo.yml

    id: card
    label: Card
    description: A reusable card component
    type: component

    props:
    kind:
    type: string
    default: button
    text:
    type: string
    default: Default text

    examples:
    primary:
    title: Primary card
    description: A card with a button
    props:
    kind: button
    text: Click me

    secondary:
    title: Secondary card
    description: A card with a link
    props:
    kind: link
    text: Go there
    then add twig file card.html.twig

    {% if kind == 'button' %}
    {{ text }}
    {% elseif kind == 'link' %}
    {{ text }}
    {% else %}
    {{ text }}
    {% endif %}

    and then render in node or page.html.twig

  • 🇫🇷France pdureau Paris

    Since Introduce component variants to SDC Active , we have introduced variant in SDC definition:

    variants:
      primary:
        title: Primary
        description: ...
      secondary:
        title: Secondary
        description: ...
      tertiary:
        title: Tertiary
        description: ...

    This simple notation covers the majority Introduce component variants to SDC Active of the use cases discovered in public design systems and projects.

    However, it fails to express advanced 2 use cases:

    When there is no explicit "variant" prop upstream documentation

    Variants are called "variant" in upstream documentation and/or code for:

    However, they may be called:

    When proposing this "advanced notation", @alex.skrypnyk told us Introduce component variants to SDC Active , so this proposal may allow us to be more faithful to the upstream documentation sending the expected variable to the template instead of variant?

    However, the notation looks excessively complicated for renaming "variant" to "kind". Example

    name:  Card
    variants:
      primary:
        title: Primary
        description: ...
        props:
           variant: primary
      secondary:
        title: Secondary
        description: ...
        props:
           variant: secondary
      tertiary:
        title: Tertiary
        description: ...
        props:
           variant: tertiary
     ...
    props: 
      type: object
      properties:
        kind:
          title: Kind
         type: string
        enum: 
          - primary
         - secondary
         - tertiary
    slots: {}

    When a variant is the combination of 2 or more enums

    In Bulma, what we call "variant" can sometimes be understood as a combination of "color" and "version". Example: https://bulma.io/documentation/elements/button/

    In this case, the advanced notation proposal looks useful:

    name:  Button
    variants:
      primary_light:
        title: Primary Light
        props:
           color: primary
           version: light
      primary:
        title: Primary dark
        props:
           color: primary
           version: dark
      secondary:
        title: Secondary light
        props:
           color: secondary
           version: light
       ...
    props: 
      type: object
      properties:
        color:
          title: Color
         type: string
         enum: 
          - primary
         -  link
        version:
          title: Version
         type: string
         enum: 
          - dark
         -  light
    slots: {}

    Conclusion

    So, with this advanced notation, what will be the processing? If the chosen variant as a non empty "props" property, we send the value of the props insetad of the "variant" variable?

    It will allow us to mix the simple notation and the advanced one. Example:

    name:  Button
    variants:
      foo:
        title: Foo
      bar:
        title: Bar
        props:
           color: primary
           version: dark
       ...
    props:
      type: object
      properties:
        color: {...}
        version: {...}
    slots: {}

    If foo is selected, variant = foo will be sent to the template. If bar is selected, color = primary and version = dark will be sent to the template.

    I am still not 100% convinced by this proposal because it is always possible to pick only one of the enum (color OR version in this example) as the "glorified" variant enum. But there is something interesting to explore here anyway.

Production build 0.71.5 2024