Skip to content

feat: support story tags and hide !dev stories from the sidebar - #969

Open
officialasishkumar wants to merge 1 commit into
storybookjs:nextfrom
officialasishkumar:feat/story-tags
Open

officialasishkumar wants to merge 1 commit into
storybookjs:nextfrom
officialasishkumar:feat/story-tags

Conversation

@officialasishkumar

Copy link
Copy Markdown
Contributor

Issue: #866

What I did

Every entry in the on-device story index got the fixed tags ['story'], so the tags set in preview, meta and stories never reached the index and Storybook's tag behaviour didn't work on device. The most visible gap is tags: ['!dev'], the documented way to keep a story out of the sidebar, which did nothing.

This puts the real tags in the index, the same way Storybook's StoryIndexGenerator does for the web, and makes the sidebar respect dev like the web manager's static filter. It's the groundwork #866 needs: tags now exist in the index for the UI and tools to use. It doesn't add tag badges to the sidebar, since how they should look still needs deciding.

Changes:

  • storyTags.ts (new): combineStoryTags starts from the default dev, test and manifest tags, then applies the project, meta and story tags with combineTags from storybook/internal/csf, so !tag removes a tag added higher up. Metas and stories with a play function get play-fn after their own tags, as CsfFile does.
  • prepareStories: reads tags from plain CSF and from CSF factories (on input, including .extend()), and takes a new optional projectTags option. start() and updateView() pass the tags of the preview annotations, which covers both a plain preview and definePreview.
  • buildIndex: this backs the channel server's /index.json and the MCP server. It uses the meta and story tags that CsfFile already parses, and reads the static tags of the preview file with readConfig, as the web does. If tags exists but isn't a static string array, it warns. A preview that can't be read statically adds no tags.
  • Sidebar: View passes a static-filter to transformStoryIndexToStoriesHash, so entries without dev are left out, along with any groups that would be empty. With no initial or persisted selection, the first story shown in the sidebar is selected rather than the first entry in the index, so a hidden story isn't opened on launch. Hidden stories stay in the index and can still be selected by id, for example from a deep link, initialSelection or the websocket channel.
  • Docs: new "Using tags" section in docs/docs/intro/writing-stories.md.
  • Changeset: minor for @storybook/react-native.

Tests:

  • prepareStories.test.ts: project, meta and story tags with negation, CSF2 function stories, play-fn, and CSF factories including .extend().
  • storyTags.test.ts: the tag helpers, and SIDEBAR_FILTERS passed through transformStoryIndexToStoriesHash.
  • View.test.ts: the default selection skips a !dev story.

buildIndex has no jest test because storybook/internal/common and csf-tools only load as ESM under this jest setup. That's also why channelServer.test.ts mocks it.

How to test

pnpm build
pnpm --filter @storybook/react-native test

I ran the @storybook/react-native jest suite (15 suites, 88 tests), check:types, ESLint and Prettier on the changed files. I also called buildIndex from the built package against examples/expo-example. With a temporary tags: ['custom'] in its definePreview preview and a temporary tags: ['!dev'] story, every entry got custom, the hidden story lost dev, and the factory story with a play function got play-fn.

To try it on device, add tags: ['!dev'] to a story in examples/expo-example and run pnpm example. The story disappears from the sidebar and search, and a component whose stories are all hidden disappears too.

  • Does this need a new example in examples/expo-example? No
  • Does this need an update to the documentation? Yes, included in this PR

Every entry in the on-device story index was given the fixed tags
`['story']`, so the `tags` set in preview, meta and stories were lost and
Storybook's tag semantics did not work on device. Most visibly, the
documented `tags: ['!dev']` way to keep a story out of the sidebar had no
effect.

Index entries now get their tags the way Storybook's index generator
does for the web: the default `dev`, `test` and `manifest` tags, then the
project, meta and story tags, combined with `combineTags` so `!tag`
removes a tag added at a higher level. Metas and stories with a play
function get `play-fn` after their own tags, like CsfFile does.

- prepareStories reads the tags of plain CSF and CSF factories (from
  `input`), and takes the project tags as a new optional `projectTags`
  option. start() and updateView() pass the tags of the preview
  annotations.
- buildIndex, used by the channel server's /index.json and the MCP
  server, reads the meta and story tags parsed by CsfFile and the static
  `tags` of the preview file, so it reports the same tags.
- The sidebar uses a static filter like the web manager: entries without
  the `dev` tag are left out of the story hash, and so are groups that
  only hold hidden stories. When there is no initial or persisted
  selection, the first story shown in the sidebar is selected instead of
  the first entry in the index. Hidden stories can still be selected by
  id, for example from a deep link or `initialSelection`.

The writing stories docs gain a "Using tags" section.

Refs storybookjs#866
@changeset-bot

changeset-bot Bot commented Nov 11, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: f28594d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@storybook/react-native Minor
@storybook/addon-ondevice-actions Minor
@storybook/addon-ondevice-backgrounds Minor
@storybook/addon-ondevice-controls Minor
@storybook/addon-ondevice-notes Minor
@storybook/react-native-theming Minor
@storybook/react-native-ui-common Minor
@storybook/react-native-ui-lite Minor
@storybook/react-native-ui Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

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

Review Status Commit Review trigger
📝 Code Review ❌ Failed 2026-11-11T15:54:39.405552Z
We couldn’t complete this review. Comment @codex review to try again.
f28594d PR opened
ℹ️ 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.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dannyhw

dannyhw commented Nov 11, 2026

Copy link
Copy Markdown
Member

could you include screenshots please?

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants