Skip to content

[Documentation]: Add documentation for multiple conditional visibility (OR logic) in argTypes using duplicate key workaround #34507

@thinnakrit

Description

@thinnakrit

Describe the problem

Summary

The current Storybook documentation for conditional controls (if) only covers single-condition visibility. There is no documented pattern for showing a control when any one of multiple args matches a condition (OR logic). This issue requests adding documentation — or at minimum a recipe/example — for achieving this using a duplicate-key workaround.


Problem

The if field in argTypes supports only a single condition:

'loading.hasOverline': {
  if: { arg: 'loading.hasLabel', eq: true }, // only shows when hasLabel is true
}

There is currently no built-in OR syntax such as:

if: [{ arg: 'loading.hasLabel', eq: true }, { arg: 'loading.hasValue', eq: true }]

This makes it impossible out-of-the-box to show a control when either of two args is active.


Workaround Discovery (Use Case)

While building a ListItem component story, I needed to show a loading.hasOverline skeleton control whenever either loading.hasLabel or loading.hasValue is true.

The solution was to declare two separate argType keys pointing to the same name, each with a different if condition:

argTypes: {
  'loading.hasOverline_label': {
    name: 'loading.hasOverline',        // <-- same display name
    if: { arg: 'loading.hasLabel', eq: true },
    control: { type: 'boolean' },
    description: 'Show skeleton for overline',
    table: { category: 'State' },
  },
  'loading.hasOverline_value': {
    name: 'loading.hasOverline',        // <-- same display name
    if: { arg: 'loading.hasValue', eq: true },
    control: { type: 'boolean' },
    description: 'Show skeleton for overline',
    table: { category: 'State' },
  },
}
  • loading.hasOverline_label appears when loading.hasLabel === true
  • loading.hasOverline_value appears when loading.hasValue === true
  • Both render under the label loading.hasOverline — so the UX looks like a single control
  • In the render function, both values are merged with ||:
const loading = {
  hasOverline: args['loading.hasOverline_label'] || args['loading.hasOverline_value'],
  hasLabel: args['loading.hasLabel'],
  hasValue: args['loading.hasValue'],
};

What Should Be Documented

  1. The limitation: if currently only supports a single condition (no OR/AND between multiple args)
  2. The duplicate-key workaround: Use unique internal keys with the same name value, each with a separate if
  3. How to consume in render: Merge the duplicate values in the render function using || (or && for AND logic)
  4. Caveats: The two controls are independent booleans — if the user toggles one and then activates the other condition, the second key's value starts from its default

Proposed Location


Additional Context

  • Storybook version: (latest)
  • Framework: React + Vite
  • This pattern is useful for components where a sub-control should appear regardless of which parent toggle is on

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions