fix(react): show explicit false boolean props in Show Code source#34661
fix(react): show explicit false boolean props in Show Code source#34661creazyfrog wants to merge 1 commit intostorybookjs:nextfrom
Conversation
📝 WalkthroughWalkthroughThe JSX renderer now disables boolean shorthand syntax by default, so boolean props are rendered explicitly as Changes
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. Review rate limit: 5/8 reviews remaining, refill in 18 minutes and 48 seconds.Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
code/renderers/react/src/docs/jsxDecorator.test.tsx (1)
74-91: ⚡ Quick winAdd 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/defaultOptskeeps 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
📒 Files selected for processing (2)
code/renderers/react/src/docs/jsxDecorator.test.tsxcode/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>
d39a2d8 to
e5c8118
Compare
There was a problem hiding this comment.
🧹 Nitpick comments (1)
code/renderers/react/src/docs/jsxDecorator.test.tsx (1)
74-91: ⚡ Quick winAdd one test for the default path (without explicitly passing
useBooleanShorthandSyntax)These tests validate the override path, but they won’t catch regressions if
defaultOptsinjsxDecorator.tsxchanges again. Add a case that callsrenderJsx(..., {})(orjsxDecorator) and still expectsdisabled={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
📒 Files selected for processing (2)
code/renderers/react/src/docs/jsxDecorator.test.tsxcode/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
Fixes #30704
What
Boolean props explicitly set to
falseare 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:
After:
Root cause
Storybook uses
@7rulnik/react-element-to-jsx-string(a fork ofreact-element-to-jsx-string) to render the JSX source string. InsideformatProp.jsthis condition silently drops anyfalseboolean prop that has no matching entry in the component's staticReact.defaultProps:Modern TypeScript components use function-parameter defaults instead of
Component.defaultProps, so!hasDefaultValueis almost alwaystrue, meaning every explicitfalseprop is discarded.Fix
Set
useBooleanShorthandSyntax: falseindefaultOptsinsidejsxDecorator.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 (
disabledinstead ofdisabled={true}) can still opt in per-story:Changes
code/renderers/react/src/docs/jsxDecorator.tsx— adduseBooleanShorthandSyntax: falsetodefaultOptscode/renderers/react/src/docs/jsxDecorator.test.tsx— add two tests:falseprop rendered explicitly,trueprop rendered explicitlyAI 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
Tests