Skip to content

Svelte: Add CSF factories with definePreview - #36669

Merged
JReinhold merged 5 commits into
nextfrom
jeppe/sb-2211-svelte-support-csf4-factories-in-regular-csf-files
Oct 20, 2026
Merged

JReinhold merged 5 commits into
nextfrom
jeppe/sb-2211-svelte-support-csf4-factories-in-regular-csf-files

Conversation

@JReinhold

@JReinhold JReinhold commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Closes #

What I did

Adds CSF4 factories to Svelte, for stories in .stories.ts and .stories.js files. Linear: SB-2211. Svelte CSF (.stories.svelte) builds on this in a later PR.

Summary

// .storybook/preview.ts
import { definePreview } from '@storybook/sveltekit'; // or '@storybook/svelte-vite'
export default definePreview({ addons: [addonDocs()] });

// Button.stories.ts
const meta = preview.meta({ component: Button, args: { size: 'large' } });
export const Primary = meta.story({ args: { label: 'Hi' } }); // label is required, size is optional
export const Extended = Primary.extend({ args: { label: 'Extended' } });
 @storybook/svelte
+  __definePreview          # adds entry-preview and entry-preview-docs, because CSF4 mode ignores preset previewAnnotations
+  SveltePreview, SvelteMeta, SvelteStory, SvelteTypes
 @storybook/svelte-vite
+  definePreview            # re-export of __definePreview
 @storybook/sveltekit
+  definePreview            # also adds the SvelteKit mocks (decorator and beforeEach)
+  SvelteKitPreview, SvelteKitTypes   # types parameters.sveltekit_experimental

preview.meta() infers args from the Svelte component props, with the same rules as React and Vue: args set in meta are optional in stories, preview.type<>(), meta.type<>() and decorators add args, and a component with unknown props (the *.svelte shim or any) takes any args.

Choices to review:

  • parameters.sveltekit_experimental is now typed, so I fixed the types to accept what the mocks accept. Before, CSF3 parameters were untyped, so nobody saw these errors. The documented state: { page } alone, enhance: () => {} and SvelteKit's page.error were rejected. Now each nested mock object is partial, callbacks can return anything, and page.error is { message: string }.
  • Two shared CSF3 test fixtures changed a little, so that the factory fixture type-checks without as any: LoaderStoryComponent takes loaded as optional, and InputFilledStoryComponent types its props as Record<string, unknown>.

Follow-ups, recorded on SB-2211 and not in this PR:

  1. A story render must return a component whose props accept every story arg (SvelteRenderer['storyResult'] is typed by args). Factories are a bit stricter here than CSF3.
  2. meta.story() accepts unknown args when the story also sets a required arg. The overload is the same in React and Vue, so the fix belongs in shared code.

Evidence

  • Type tests: renderers/svelte/src/csf-factories.test.ts has the Vue3 cases plus snippet props, $bindable props, callback props, generic components and a component without props. svelte-check passes, and every @ts-expect-error in it is used.
  • Runtime: portable-stories-factory.test.ts runs every factory story with Story.run() and snapshots the DOM.
  • SvelteKit: a runtime test fails when the wrapper doesn't add the SvelteKit mocks. Type tests cover the wrapper without addons and the mock parameter types.
  • Sandbox (svelte-kit/skeleton-ts), with the preview switched to definePreview and two factory stories files:
    • Vitest (addon-vitest, Chromium): 3 of 3 stories pass, including a story that reads the mocked $app/state.
    • svelte-check reports a missing required arg and a wrong sveltekit_experimental type in the factory files.
    • In the Storybook UI, the stories render and their play functions pass:

Extended story built with Primary.extend(): the play function passes
State story: the SvelteKit page mock set in meta parameters is rendered

Merge Danger

Door: two-way. The change adds new exports and doesn't change existing ones.

Blast Radius: small. Existing CSF3 and Svelte CSF files keep working. The only change that existing users can see is the type of SvelteKitParameters, which is now less strict than before.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

  1. Run a sandbox: yarn task sandbox --start-from auto --template svelte-kit/skeleton-ts.

  2. In .storybook/main.ts, set stories to ["../src/factories/*.stories.ts"] and remove previewAnnotations.

  3. Replace .storybook/preview.ts with:

    import addonDocs from '@storybook/addon-docs';
    import { definePreview } from '@storybook/sveltekit';
    
    export default definePreview({ addons: [addonDocs()], tags: ['vitest'] });
  4. Add src/factories/Button.stories.ts:

    import preview from '../../.storybook/preview';
    import Button from '../stories/Button.svelte';
    
    const meta = preview.meta({ component: Button, args: { size: 'large' } });
    export const Primary = meta.story({ args: { label: 'Primary', primary: true } });
    export const Extended = Primary.extend({ args: { label: 'Extended' } });
  5. Run yarn storybook. Check that both stories render a large primary button.

  6. Run yarn vitest --run --project storybook. Both stories pass.

  7. Remove label from Primary and run yarn check. svelte-check reports that label is missing.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

The docs for Svelte factories come with the Svelte CSF support (SB-2215).

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary Release - 🚫 Not run

This PR does not have a canary release associated.

In-repo PRs: add the ci:canary label. Later pushes republish while the label remains.

🤖 Generated with Claude Code

JReinhold and others added 3 commits October 7, 2026 22:21
preview.meta() infers args from the props of a Svelte component, like
the React and Vue renderers. definePreview adds the renderer's preview
annotations itself, because CSF factories mode ignores preset
previewAnnotations.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The SvelteKit definePreview adds the SvelteKit mocks and types
parameters.sveltekit_experimental. The types now accept what the mocks
accept at runtime: each nested mock is optional, callbacks may return
anything, and page.error is SvelteKit's error object.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@JReinhold JReinhold added feature request ci:normal Run our default set of CI jobs (choose this for most PRs). qa:needed Pull Requests that will need manual QA prior to release. labels Oct 7, 2026
@JReinhold JReinhold self-assigned this Oct 7, 2026
@JReinhold

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Oct 7, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 48189150-f327-489b-ac21-1e212a254599
📥 Commits

Reviewing files that changed from the base of the PR and between a532e8a and b7944cc.

⛔ Files ignored due to path filters (1)
  • code/renderers/svelte/src/__test__/composeStories/__snapshots__/portable-stories-factory.test.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (18)
  • code/frameworks/svelte-vite/src/index.test.ts
  • code/frameworks/svelte-vite/src/index.ts
  • code/frameworks/sveltekit/src/csf-factories.test.ts
  • code/frameworks/sveltekit/src/index.ts
  • code/frameworks/sveltekit/src/types.ts
  • code/frameworks/sveltekit/vitest.config.ts
  • code/renderers/svelte/src/__test__/Divider.svelte
  • code/renderers/svelte/src/__test__/Input.svelte
  • code/renderers/svelte/src/__test__/Layout.svelte
  • code/renderers/svelte/src/__test__/List.svelte
  • code/renderers/svelte/src/__test__/composeStories/Button.csf4.stories.ts
  • code/renderers/svelte/src/__test__/composeStories/InputFilledStoryComponent.svelte
  • code/renderers/svelte/src/__test__/composeStories/LoaderStoryComponent.svelte
  • code/renderers/svelte/src/__test__/composeStories/portable-stories-factory.test.ts
  • code/renderers/svelte/src/csf-factories.test.ts
  • code/renderers/svelte/src/index.ts
  • code/renderers/svelte/src/preview.ts
  • code/renderers/svelte/src/types.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


Walkthrough

The Svelte renderer adds typed preview and story factories. The Svelte Vite and SvelteKit frameworks expose preview APIs. SvelteKit adds typed experimental parameters and mock shapes. Tests cover factory typing and portable story composition.

Changes

Svelte Preview and CSF

Layer / File(s) Summary
Svelte preview types and exports
code/renderers/svelte/src/preview.ts, code/renderers/svelte/src/types.ts, code/renderers/svelte/src/index.ts
The renderer adds typed preview, meta, and story interfaces, component argument inference, and public exports for the preview API and Svelte types.
Svelte CSF factory type coverage
code/renderers/svelte/src/csf-factories.test.ts, code/renderers/svelte/src/__test__/*.svelte
Type tests and Svelte fixtures cover component props, snippets, bindable values, generic components, required arguments, decorators, and composed story arguments.
Framework preview APIs and SvelteKit parameters
code/frameworks/svelte-vite/src/index.ts, code/frameworks/svelte-vite/src/index.test.ts, code/frameworks/sveltekit/src/index.ts, code/frameworks/sveltekit/src/types.ts, code/frameworks/sveltekit/src/csf-factories.test.ts, code/frameworks/sveltekit/vitest.config.ts
Svelte Vite re-exports the renderer preview API. SvelteKit adds a typed wrapper that prepends its preview addon, updates parameter and mock types, registers the Svelte plugin in Vitest, and tests the resulting types.
Portable story composition coverage
code/renderers/svelte/src/__test__/composeStories/*
CSF4 stories exercise decorators, custom rendering, input interaction, loaders, and story extension. Portable-story tests run stories, check composed arguments, and compare snapshots.

Sequence Diagram(s)

sequenceDiagram
  participant Consumer
  participant SvelteKitDefinePreview
  participant SvelteDefinePreview
  Consumer->>SvelteKitDefinePreview: Project annotations and optional addons
  SvelteKitDefinePreview->>SvelteDefinePreview: Pass annotations with SvelteKit addon prepended
  SvelteDefinePreview-->>SvelteKitDefinePreview: Return typed Svelte preview
  SvelteKitDefinePreview-->>Consumer: Return typed SvelteKit preview
Loading

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to b7944

No issue requiring a change before merge was identified; normal validation remains appropriate.

✨ Finishing Touches 💡 1
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

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

@JReinhold
JReinhold marked this pull request as ready for review October 8, 2026 20:20
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T20:24:51.163097Z b7944cc Draft marked ready
🔒 Security Review ✅ Completed 2026-10-08T20:25:00.191456Z b7944cc Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@kasperpeulen kasperpeulen left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good, nice work! One type issue inline that I'd fix before merging.

Comment thread code/renderers/svelte/src/preview.ts
JReinhold and others added 2 commits October 19, 2026 14:15
svelte-check types a runes component without `$props()` as
`Component<Record<string, never>>`, so every arg had to be `never`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@JReinhold
JReinhold merged commit 80190cc into next Oct 20, 2026
109 of 112 checks passed
@JReinhold
JReinhold deleted the jeppe/sb-2211-svelte-support-csf4-factories-in-regular-csf-files branch October 20, 2026 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). feature request qa:needed Pull Requests that will need manual QA prior to release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants