Skip to content

fix(react): show explicit false boolean props in Show Code source#34661

Open
creazyfrog wants to merge 1 commit intostorybookjs:nextfrom
creazyfrog:fix/false-props-not-shown-in-source-react
Open

fix(react): show explicit false boolean props in Show Code source#34661
creazyfrog wants to merge 1 commit intostorybookjs:nextfrom
creazyfrog:fix/false-props-not-shown-in-source-react

Conversation

@creazyfrog
Copy link
Copy Markdown

@creazyfrog creazyfrog commented Apr 30, 2026

Fixes #30704

What

Boolean props explicitly set to false are silently omitted from the Show Code source snippet in React stories, even though they are meaningfully different from not passing the prop at all.

Before:

// Story args: { loading: false }
<Button />   // `loading` nowhere to be seen

After:

<Button loading={false} />

Root cause

Storybook uses @7rulnik/react-element-to-jsx-string (a fork of react-element-to-jsx-string) to render the JSX source string. Inside formatProp.js this condition silently drops any false boolean prop that has no matching entry in the component's static React.defaultProps:

if (useBooleanShorthandSyntax && formattedPropValue === '{false}' && !hasDefaultValue) {
  attributeFormattedInline = '';   // ← dropped
}

Modern TypeScript components use function-parameter defaults instead of Component.defaultProps, so !hasDefaultValue is almost always true, meaning every explicit false prop is discarded.

Fix

Set useBooleanShorthandSyntax: false in defaultOpts inside jsxDecorator.tsx. This tells the library to always emit boolean props as explicit JSX values (disabled={false}, disabled={true}) instead of applying shorthand rules.

Users who prefer the shorthand (disabled instead of disabled={true}) can still opt in per-story:

parameters: {
  jsx: { useBooleanShorthandSyntax: true },
}

Changes

  • code/renderers/react/src/docs/jsxDecorator.tsx — add useBooleanShorthandSyntax: false to defaultOpts
  • code/renderers/react/src/docs/jsxDecorator.test.tsx — add two tests: false prop rendered explicitly, true prop rendered explicitly

AI disclosure

This fix was developed with the assistance of Claude (AI). The root-cause analysis, code change, and tests were reviewed by a human contributor before submission.

Summary by CodeRabbit

  • New Features

    • Code examples' "Show Code" now render boolean props explicitly (e.g., disabled={false}, disabled={true}) by default for clearer JSX output.
  • Tests

    • Added test coverage verifying explicit boolean prop rendering when shorthand syntax is disabled.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 30, 2026

📝 Walkthrough

Walkthrough

The JSX renderer now disables boolean shorthand syntax by default, so boolean props are rendered explicitly as prop={true} or prop={false}. Tests were added to verify explicit rendering for both true and false values.

Changes

Cohort / File(s) Summary
JSX boolean rendering & tests
code/renderers/react/src/docs/jsxDecorator.tsx, code/renderers/react/src/docs/jsxDecorator.test.tsx
Set useBooleanShorthandSyntax: false in JSX code generation to force explicit boolean prop output; added/updated tests asserting disabled={false} and disabled={true} appear explicitly in rendered JSX.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 5/8 reviews remaining, refill in 18 minutes and 48 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
code/renderers/react/src/docs/jsxDecorator.test.tsx (1)

74-91: ⚡ Quick win

Add one regression test for the default option path (without passing useBooleanShorthandSyntax).

These tests validate explicit behavior when the option is passed, but they don’t verify that jsxDecorator/defaultOpts keeps that behavior by default. A single assertion through the default flow would lock in the PR’s main contract.

Suggested test shape
+it('renders false booleans explicitly by default through jsxDecorator options', () => {
+  function Button({ disabled }: { disabled?: boolean }) {
+    return <button disabled={disabled}>click</button>;
+  }
+
+  // no useBooleanShorthandSyntax override
+  expect(renderJsx(<Button disabled={false} />, {})).toMatchInlineSnapshot(
+    `<Button disabled={false} />`
+  );
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/renderers/react/src/docs/jsxDecorator.test.tsx` around lines 74 - 91,
Add a regression test that exercises the default option path by calling
renderJsx without the useBooleanShorthandSyntax option and asserting boolean
props are still rendered explicitly; create a test (e.g., "false boolean values
are rendered explicitly by default") that defines a local Button({ disabled }: {
disabled?: boolean }) component and expects renderJsx(<Button disabled={false}
/>) toMatchInlineSnapshot showing <Button disabled={false} /> to ensure
jsxDecorator/defaultOpts preserves the explicit-false behavior by default.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/renderers/react/src/docs/jsxDecorator.test.tsx`:
- Around line 74-91: Add a regression test that exercises the default option
path by calling renderJsx without the useBooleanShorthandSyntax option and
asserting boolean props are still rendered explicitly; create a test (e.g.,
"false boolean values are rendered explicitly by default") that defines a local
Button({ disabled }: { disabled?: boolean }) component and expects
renderJsx(<Button disabled={false} />) toMatchInlineSnapshot showing <Button
disabled={false} /> to ensure jsxDecorator/defaultOpts preserves the
explicit-false behavior by default.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1d6055c2-1c9a-46ef-a82c-7d3654447dda

📥 Commits

Reviewing files that changed from the base of the PR and between cf07244 and d39a2d8.

📒 Files selected for processing (2)
  • code/renderers/react/src/docs/jsxDecorator.test.tsx
  • code/renderers/react/src/docs/jsxDecorator.tsx

Fixes storybookjs#30704

The underlying `react-element-to-jsx-string` library (used via the
`@7rulnik/react-element-to-jsx-string` fork) suppresses any boolean prop
whose value is `false` and that has no matching entry in the component's
static `React.defaultProps`. This is the norm for modern TypeScript
components that use function parameter defaults instead of `defaultProps`.

As a result, stories that explicitly pass e.g. `loading={false}` or
`disabled={false}` show a source snippet that omits those props entirely,
making the generated code incorrect and misleading to readers.

Root cause (in `formatProp.js`):
  if (useBooleanShorthandSyntax && formattedPropValue === '{false}' && !hasDefaultValue) {
    attributeFormattedInline = '';   // silently dropped
  }

Fix: set `useBooleanShorthandSyntax: false` in `defaultOpts` so both
`true` and `false` boolean props are always emitted as explicit JSX
attribute values (`disabled={false}`, `disabled={true}`). This is
unambiguous and more informative in a documentation context.

Users who prefer the shorthand (`disabled` for true) can still opt in
via `parameters.jsx.useBooleanShorthandSyntax = true`.

Tests added for both `false` and `true` explicit rendering.

AI disclosure: this fix was developed with the assistance of Claude.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@creazyfrog creazyfrog force-pushed the fix/false-props-not-shown-in-source-react branch from d39a2d8 to e5c8118 Compare April 30, 2026 08:40
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
code/renderers/react/src/docs/jsxDecorator.test.tsx (1)

74-91: ⚡ Quick win

Add one test for the default path (without explicitly passing useBooleanShorthandSyntax)

These tests validate the override path, but they won’t catch regressions if defaultOpts in jsxDecorator.tsx changes again. Add a case that calls renderJsx(..., {}) (or jsxDecorator) and still expects disabled={false} to be printed explicitly.

Proposed test addition
   it('true boolean values are rendered as explicit value when useBooleanShorthandSyntax is false', () => {
     function Button({ disabled }: { disabled?: boolean }) {
       return <button disabled={disabled}>click</button>;
     }
     expect(
       renderJsx(<Button disabled={true} />, { useBooleanShorthandSyntax: false })
     ).toMatchInlineSnapshot(`<Button disabled={true} />`);
   });
+
+  it('false boolean values are rendered explicitly by default options', () => {
+    function Button({ disabled }: { disabled?: boolean }) {
+      return <button disabled={disabled}>click</button>;
+    }
+    expect(renderJsx(<Button disabled={false} />, {})).toMatchInlineSnapshot(
+      `<Button disabled={false} />`
+    );
+  });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code/renderers/react/src/docs/jsxDecorator.test.tsx` around lines 74 - 91,
Add a test in jsxDecorator.test.tsx that mirrors the existing "false boolean
values are rendered explicitly" case but invokes renderJsx without the explicit
option (call renderJsx(<Button disabled={false} />, {}) or simply
renderJsx(<Button disabled={false} />)) to exercise the defaultOpts path; use
the same Button component as the other tests and assert the snapshot equals
`<Button disabled={false} />` to ensure default behavior (renderJsx /
jsxDecorator and the useBooleanShorthandSyntax default) continues to print false
booleans explicitly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code/renderers/react/src/docs/jsxDecorator.test.tsx`:
- Around line 74-91: Add a test in jsxDecorator.test.tsx that mirrors the
existing "false boolean values are rendered explicitly" case but invokes
renderJsx without the explicit option (call renderJsx(<Button disabled={false}
/>, {}) or simply renderJsx(<Button disabled={false} />)) to exercise the
defaultOpts path; use the same Button component as the other tests and assert
the snapshot equals `<Button disabled={false} />` to ensure default behavior
(renderJsx / jsxDecorator and the useBooleanShorthandSyntax default) continues
to print false booleans explicitly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e810ab09-886d-460d-88b6-a360e9474d6d

📥 Commits

Reviewing files that changed from the base of the PR and between d39a2d8 and e5c8118.

📒 Files selected for processing (2)
  • code/renderers/react/src/docs/jsxDecorator.test.tsx
  • code/renderers/react/src/docs/jsxDecorator.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/renderers/react/src/docs/jsxDecorator.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Storybook false props are not appearing in the show code react

1 participant