Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to hide a story from the sidebar #9209

Closed
rafaelalmeidatk opened this issue Dec 20, 2019 · 86 comments · Fixed by #26634
Closed

Add an option to hide a story from the sidebar #9209

rafaelalmeidatk opened this issue Dec 20, 2019 · 86 comments · Fixed by #26634

Comments

@rafaelalmeidatk
Copy link
Contributor

Is your feature request related to a problem? Please describe.
I am doing visual regression testing with Storybook iframes. I have some docs pages that aren't specific for a single component, for example, I have an "icons" page that shows all the icons of the library in a grid. I would like to test all these icons but since they are on a docs page, I don't have the iframe available.

Describe the solution you'd like
I would like to be able to create stories that are hidden on the sidebar but can still be accessible by the URL. Perhaps a per-story configuration.

Describe alternatives you've considered
I can create a story just for the icons grid, but it is redundant and a bit out of place since I already have the icons doc page that has a lot more info

Are you able to assist bring the feature to reality?
Yes, if the suggestion makes sense for the project, I can find some time to implement it

@stale
Copy link

stale bot commented Feb 10, 2020

Hey there, it's me again! I am going close this issue to help our maintainers focus on the current development roadmap instead. If the issue mentioned is still a concern, please open a new ticket and mention this old one. Cheers and thanks for using Storybook!

@stale stale bot closed this as completed Feb 10, 2020
@shilman shilman reopened this Feb 10, 2020
@stale stale bot removed the inactive label Feb 10, 2020
@rafaelalmeidatk
Copy link
Contributor Author

FWIW, I solved my issue without this feature using the storiesOf API and a env var:

import React from 'react';
import { storiesOf } from '@storybook/react';
import IconsGrid from './IconsGrid';

if (process.env.STORYBOOK_VISUAL_TESTING === 'true') {
  storiesOf('VisualTests', module).add('icons', () => <IconsGrid />);
  storiesOf('VisualTests', module).add('icons-color-size', () => (
    <IconsGrid color="#e04c36" size="24px" />
  ));
}

I still think the feature is useful because my workaround requires the usage of storiesOf so I can't use CSF, if I wanted to hide a specific story in a file with other stories, it would be weird to have the two formats mixed.

@evanmwillhite
Copy link

I'm interested in this functionality as well. Our use-case is we're leveraging stories in Storybook and a different app as well (the CSF format is awesome for many reasons!). If we could flag a story as hidden from the Storybook UI, it would allow flexibility in writing them for either or both places.

@shilman
Copy link
Member

shilman commented Feb 17, 2020

@evanmwillhite ooh! can you share more about your CSF usage?! super curious.

@evanmwillhite
Copy link

@shilman for sure! We have a need for a fully customizable "style guide" (a la Carbon Design System) so we've built a Gatsby theme for that as it offers design and content management flexibility. But for the components section of that style guide - specifically when showing components and their code - we love the idea of being able to use Storybook's generated components for that as it's solved that problem so well (and Storybook is already our choice for component library and development environment so we're invested). But as you can probably imagine, the component library may contain a lot more components and display them differently than a curated style guide (different audiences). There's probably a number of ways to solve this problem, but our first thought was that it would be nice if Storybook could generate the component, but we could specify to hide it from the Storybook menu. We're looking into writing an addon for this right now actually, but any insights you might have would be super helpful!

@shilman
Copy link
Member

shilman commented Feb 17, 2020

@evanmwillhite nice!! yeah CSF makes that pretty easy 😁

as for hiding the story from the sidebar, I think we'll probably end up adding it at some point, both based on the upvotes here and I'm pretty sure it's come up other places as well. But I don't have a timeline yet. It should be a pretty simple change, tho perhaps there are a few corner cases to work out. Any proposed APIs for that? Currently the API for hiding it from docs is docs: { disable: true } ... sidebar: { disable: true } cc @ndelangen

@techninja
Copy link

@shilman Thanks for the update here, yeah we'd totally love to have that. Perhaps something like sidebarHide: ['variant1', 'variant2']. The big difference between the disable list being that we still build everything for the story variants.

@shilman
Copy link
Member

shilman commented Feb 17, 2020

@techninja "build everything"? my proposal for sidebar: {disable:true} would be that the story still gets added to the store, so it would be snapshottable/browseable-by-url/etc.

@techninja
Copy link

Yep, sorry that's what I was referring to. I've been attempting to do something like this in an addon though it's not entirely clear the best way to do so, and the docs are a little lacking on any APIs surrounding this.

@stubar
Copy link

stubar commented Feb 18, 2020

For those who can't wait for the above proposal, here's a little work around

  1. Choose some sort of keyword prefix for your hidden stories e.g. _hidden_
  2. Add stories you want hidden using the above prefix
 storiesOf('components', module).add('_hidden_Hero', () => {...
  1. Create a file called .storybook/manager-head.html
  2. Add the following to this file
<style>
 [title^='_hidden_']{display: none !important}
</style>

@stale stale bot added the inactive label Mar 11, 2020
@rafaelalmeidatk
Copy link
Contributor Author

not stale

@matheo
Copy link
Member

matheo commented Mar 29, 2020

sidebar: { disable: true } will be nice to have for v6.0.0

What are the corner cases @shilman?

@shilman
Copy link
Member

shilman commented Mar 30, 2020

No corner cases AFAIK. Just adds complexity.

@hipstersmoothie
Copy link
Contributor

This would be a killer feature to have with addon-docs.

I have a bunch of mdx files with designer focused documentation. (not stories.mdx) This file generally just documents the component and references story ids to render stories. A lot of the time we want to add examples in this doc but still want it to be verified with typescript/eslint so we end up creating real stories for them.

The only problem is the sidebar gets cluttered with these stories that aren't as useful or needed when not using addon-docs


Context: We are moving to a model where the docs tab is a design focused experience and the canvas tab is more focused on devs. we don't want to inundate our devs with a bunch useless examples

@ndelangen
Copy link
Member

It fits in with tags, as this is the lower-level API we want to use to build up to having tags-filtering build-in.

@genepaul
Copy link

@ndelangen - thanks so much for this! I couldn't quite determine from the PR whether this will work for my use case, though. As mentioned above, I have a CSF file for a component that I have docs being generated from, and in that file I have a story that I don't want to show in the sidebar or on the page for that component. Instead, I have another MDX file that is demonstrating how components are used together where I might want to pull that specific story into a canvas (<Canvas of={AlertStories.Pattern}/>). If the story is filtered out by this, will I still be able to render it directly like that? Will it be removed from the <Stories/> block, but not if it's directly referenced? I know that today if you have docs.disable=true, it's removed from everything.

@genepaul
Copy link

@ndelangen - I just upgraded my storybook and used the sidebar filter function, and it works for everything I need it for! 🎉 Thanks so much for this!

@genepaul
Copy link

For others needing something like this, I added the following to my manager.js:

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('pattern');
      }
    }
  }
});

Then for any story I wanted filtered out, I just put tags: ['pattern'] in the story definition, and it filtered it out of the sidebar and autogenerated docs, but I could still use a Canvas pointing to it in custom MDX documentation.

@pascalduez
Copy link
Contributor

pascalduez commented Sep 4, 2023

For others needing something like this, I added the following to my manager.js:

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('pattern');
      }
    }
  }
});

Then for any story I wanted filtered out, I just put tags: ['pattern'] in the story definition, and it filtered it out of the sidebar and autogenerated docs, but I could still use a Canvas pointing to it in custom MDX documentation.

That's pretty nice, thanks!

I wanted to exclude some "development only" stories (where I tests regressions and else), from the published Storybook.

addons.setConfig({
  ...
});

if (process.env.NODE_ENV !== 'development') {
  addons.setConfig({
    sidebar: {
      filters: {
        devel: item => {
          return !item.tags.includes('devel');
        },
      },
    },
  });
}

@SimonHarte
Copy link

SimonHarte commented Sep 5, 2023

For others needing something like this, I added the following to my manager.js:

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('pattern');
      }
    }
  }
});

Then for any story I wanted filtered out, I just put tags: ['pattern'] in the story definition, and it filtered it out of the sidebar and autogenerated docs, but I could still use a Canvas pointing to it in custom MDX documentation.

Tagging only works in Storybook v7+ right? I'm trying to achieve the same in SB 6.5 but this example doesn't work and there's really no clear documentation that I could find for what parameters can be passed in setConfig.

@genepaul
Copy link

genepaul commented Sep 5, 2023

Yeah @SimonHarte, as noted above, this is available in SB 7.4+. Unfortunately no option I know of exists in 6.5, except for the CSS workarounds noted up above in this issue.

rajsite pushed a commit to ni/nimble that referenced this issue Sep 6, 2023
…1490)

# Pull Request

## 🤨 Rationale

The latest version of Storybook added a way to hide certain stories from
the sidebar. I've been wanting this for "internal" stories that are only
used to be composed into higher level MDX docs pages.


storybookjs/storybook#9209 (comment)


![image](https://github.com/ni/nimble/assets/10500124/35418193-4e5a-48ee-9716-bb29b12eb91d)


## 👩‍💻 Implementation

1. Update all Storybook-related dependencies to latest
- This has the unfortunate side effect of printing a huge string of
garbage to the console when you run `npm run storybook -w
@ni/nimble-components`. I believe it's caused by
storybookjs/storybook#23675 but I'm not clear
on how to apply the workaround since we don't appear to use a shared
configuration.
3. Add storybook configuration to hide stories that start with
"Internal" or "patterns" or "Tests" for the version hosted on
nimble.ni.dev (shouldn't affect PR builds or dev builds)
4. Update MDX docs for hidden sections

## 🧪 Testing

I looked to see if there were any other notable features in their
[release notes](https://github.com/storybookjs/storybook/releases) or
[blogs](https://storybook.js.org/blog/storybook-7-1/) and didn't find
much other than official support for the [Figma
addon](https://storybook.js.org/blog/figma-plugin-for-storybook/). The
only behavior change I noticed is a new badge on the Controls tab that
shows how many API entry points we document 🤷‍♀️

1. Inspected local build and PR build of Storybook to ensure expected
items are hidden
2. Poked around to see if anything else broke. 

I'll check the nimble.ni.dev/storybook after this deploys to ensure it's
actually working, but I already verified the value of
`window.location.hostname` in dev tools so I think it'll work.

## ✅ Checklist

<!--- Review the list and put an x in the boxes that apply or ~~strike
through~~ around items that don't (along with an explanation). -->

- [x] I have updated the project documentation to reflect my changes or
determined no changes are needed.
@dfidalg0
Copy link

For others needing something like this, I added the following to my manager.js:

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('pattern');
      }
    }
  }
});

Then for any story I wanted filtered out, I just put tags: ['pattern'] in the story definition, and it filtered it out of the sidebar and autogenerated docs, but I could still use a Canvas pointing to it in custom MDX documentation.

For those coming here from a search engine, addons is exported from @storybook/manager-api

@LasseMunk
Copy link

Hi can you elaborate on this ?

For others needing something like this, I added the following to my manager.js:

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('pattern');
      }
    }
  }
});

Then for any story I wanted filtered out, I just put tags: ['pattern'] in the story definition, and it filtered it out of the sidebar and autogenerated docs, but I could still use a Canvas pointing to it in custom MDX documentation.

Hi thank you for the reply !

Could you elaborate ? I am unsure where to find the manager.js to which I should set the

addons.setConfig({ sidebar: { filters: { patterns: (item) => { return !item.tags.includes('pattern'); } } } });

My usecase:

I have several mystory.stories.tsx files, that I gather / summarize in a documentation.mdx

I would like to only show the documentation.mdx in the sidebar.

@LasseMunk
Copy link

I did not see I had to install this package
https://www.npmjs.com/package/@storybook/manager-api

I created a file in .storybook directory called manager.ts and made my pattern as abovementioned.

@bastiW
Copy link

bastiW commented Sep 25, 2023

@ndelangen The filter future is not yet documented in the storybook documentation

https://storybook.js.org/docs/react/configure/features-and-behavior
https://storybook.js.org/docs/react/configure/overview#configure-storybooks-ui

P. S.
you also need to import the correct addons package

import { addons } from '@storybook/manager-api';

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('isHidden');
      }
    }
  }
});

@ndelangen
Copy link
Member

@bastiW that's correct.

I have a task to formally write this API into a RFC. (I'm hoping I'll be able to get to that task this week).

After a discussion with the core team (also welcome to outside contributors!) we'll formalize this API into the docs.

@dep
Copy link

dep commented Nov 13, 2023

How do I add "tags" to a Story when using the MDX format?

@yannbf
Copy link
Member

yannbf commented Nov 15, 2023

How do I add "tags" to a Story when using the MDX format?

Hey @dep, can you elaborate your use case? What Storybook version are you using and how are you defining your mdx stories? This change is for Storybook 7 which indexes tags as part of stories. In Storybook 7 the way mdx stories are written changed, so that you only refer to stories created in the .stories.ts|js file. In that file, tags would be defined e.g.

export const Primary = {
	tags: ['some-tag']
}

@dep
Copy link

dep commented Nov 15, 2023

@yannbf Thanks for the reply! My stories generally follow this format:

import { Markdown, Meta, Story, Canvas } from "@storybook/addon-docs";
import { Box, Card, CardActions, CardContent, Button, Typography } from "../..";
import { prettifyDocSource } from "../../utils/prettify-doc-source";
import ComponentCounts from "./utilization.md";

<Meta
  title="Components/Cards"
  component={Card}
  parameters={{
    docs: {
      transformSource: (source) => prettifyDocSource(source),
    },
    controls: {
      expanded: true,
    },
  }}
/>

# Card

Cards contain content and actions about a single subject.

Cards are surfaces that display content and actions on a single topic.

They should be easy to scan for relevant and actionable information. Elements, like text and images, should be placed on them in a way that clearly indicates hierarchy.

#### Basic Card

export const BasicCard = (args) => {
  const bull = (
    <Box
      component="span"
      sx={{ display: "inline-block", mx: "2px", transform: "scale(0.8)" }}
    ></Box>
  );
  return (
    <Card sx={{ minWidth: 275 }}>
      <CardContent>
        <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
          Word of the Day
        </Typography>
        <Typography variant="h5" component="div">
          be{bull}nev{bull}o{bull}lent
        </Typography>
        <Typography sx={{ mb: 1.5 }} color="text.secondary">
          adjective
        </Typography>
        <Typography variant="body2">
          well meaning and kindly.
          <br />
          {'"a benevolent smile"'}
        </Typography>
      </CardContent>
      <CardActions>
        <Button size="small">Learn More</Button>
      </CardActions>
    </Card>
  );
};

<Canvas>
  <Story name="Basic card"><BasicCard /></Story>
</Canvas>

'''jsx
<Card sx={{ minWidth: 275 }}>
  <CardContent>
    <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
      Word of the Day
    </Typography>
    <Typography variant="h5" component="div">
      be•nev•o•lent
    </Typography>
    <Typography sx={{ mb: 1.5 }} color="text.secondary">
      adjective
    </Typography>
    <Typography variant="body2">
      well meaning and kindly.
      <br />
      {'"a benevolent smile"'}
    </Typography>
  </CardContent>
  <CardActions>
    <Button size="small">Learn More</Button>
  </CardActions>
</Card>
'''

> #### Outlined Card

export const OutlinedCard = (args) => {
  const bull = (
    <Box
      component="span"
      sx={{ display: "inline-block", mx: "2px", transform: "scale(0.8)" }}
    ></Box>
  );
  const ExampleCard = (
    <>
      <CardContent>
        <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
          Word of the Day
        </Typography>
        <Typography variant="h5" component="div">
          be{bull}nev{bull}o{bull}lent
        </Typography>
        <Typography sx={{ mb: 1.5 }} color="text.secondary">
          adjective
        </Typography>
        <Typography variant="body2">
          well meaning and kindly.
          <br />
          {'"a benevolent smile"'}
        </Typography>
      </CardContent>
      <CardActions>
        <Button size="small">Learn More</Button>
      </CardActions>
    </>
  );
  return (
    <Box sx={{ minWidth: 275 }}>
      <Card variant="outlined">
        <>
          <CardContent>
            <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
              Word of the Day
            </Typography>
            <Typography variant="h5" component="div">
              be{bull}nev{bull}o{bull}lent
            </Typography>
            <Typography sx={{ mb: 1.5 }} color="text.secondary">
              adjective
            </Typography>
            <Typography variant="body2">
              well meaning and kindly.
              <br />
              {'"a benevolent smile"'}
            </Typography>
          </CardContent>
          <CardActions>
            <Button size="small">Learn More</Button>
          </CardActions>
        </>
      </Card>
    </Box>
  );
};

<Canvas>
  <Story name="Outlined Card"><OutlinedCard /></Story>
</Canvas>

'''jsx
<Box>
  <Card variant="outlined">
    <>
      <CardContent>
        <Typography sx={{ fontSize: 14 }} color="text.secondary" gutterBottom>
          Word of the Day
        </Typography>
        <Typography variant="h5" component="div">
          be•nev•o•lent
        </Typography>
        <Typography sx={{ mb: 1.5 }} color="text.secondary">
          adjective
        </Typography>
        <Typography variant="body2">
          well meaning and kindly.
          <br />
          {'"a benevolent smile"'}
        </Typography>
      </CardContent>
      <CardActions>
        <Button size="small">Learn More</Button>
      </CardActions>
    </>
  </Card>
</Box>
'''

I would generally like to only see a single item in the Sidebar for "Card" so our users can consume how to use a component from top to bottom.

@Clindbergh
Copy link

import { addons } from '@storybook/manager-api';

addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item) => {
        return !item.tags.includes('isHidden');
      }
    }
  }
});

To avoid any and use the full types in typescript:

import { addons } from '@storybook/manager-api';
import {API_PreparedIndexEntry, API_StatusObject} from "@storybook/types";


addons.setConfig({
  sidebar: {
    filters: {
      patterns: (item: API_PreparedIndexEntry & {
        status: Record<string, API_StatusObject | null>;
      }): boolean => {
        return !(item.tags ?? []).includes('hideInSidebar');
      }
    }
  }
});

and in your stories:

const meta: Meta<ListComponent> = {
  title: 'List',
  component: ListComponent,
  tags: ['hideInSidebar'],
  ...

with these @storybook packages in my package.json

        "@storybook/addon-controls": "^7.6.3",
        "@storybook/addon-essentials": "^7.5.3",
        "@storybook/addon-interactions": "^7.5.3",
        "@storybook/angular": "^7.5.3",
        "@storybook/core-server": "^7.5.3",
        "@storybook/jest": "^0.2.3",
        "@storybook/test-runner": "^0.13.0",
        "@storybook/testing-library": "^0.2.2",

@kylegach
Copy link
Contributor

@dep

I would generally like to only see a single item in the Sidebar for "Card" so our users can consume how to use a component from top to bottom.

Sorry for the late reply here, but just in case it's still useful, you can achieve this (for all stories) with "docs mode": https://storybook.js.org/docs/writing-docs/build-documentation.

@yuri-scarbaci-lenio
Copy link
Contributor

yuri-scarbaci-lenio commented May 10, 2024

Coming back to this,
even if the proposed solution seems to imply that

  sidebar: {
   filters: {
     patterns: (item: API_PreparedIndexEntry & {
       status: Record<string, API_StatusObject | null>;
     }): boolean => {
       return !(item.tags ?? []).includes('hideInSidebar');
     }
   }
 }

would be affecting only the list of items shown in the sidebar (since it lives under sidebar.filters)
this,
to my surprise,
is also having some sort of impact on the render phase of the story

I was expecting visiting the url because you know the url (so I can actually use it in my other stories as iframe)
I would see
image

but instead I am getting:

image

for extra reference, we need the renderer to be able to still render "as normal" when filtered in the sidebar to be able to provide documentation like this:
image

which in an era where iframe micro-frontend has somehow become a "valuable" pattern, being able to document "iframe micro front-end specific concerns" is something a documentation portal should be able to somehow allow...

@JReinhold
Copy link
Contributor

@yuri-scarbaci-lenio do I understand you correctly, that because you filtered out the story from the sidebar, when you opened the story directly with a URL, you would expect that specific story to not have the sidebar?

If so, I don't think that is a correct mental model to have.

Displaying stories only without the manager UI (sidebar, panel, toolbar) is supported by using the iframe.html URL of a story, that you get when clicking the "Open canvas in new tab" button in the top right corner. In your case that would be http://localhost:3000/iframe.html?path=/story/components-tooltipv3-examples--url-only-iframe-tooltip-no-boundries

@yannbf
Copy link
Member

yannbf commented May 15, 2024

Hey @yuri-scarbaci-lenio Thanks for elaborating, but I think it's still confusing to understand what you're trying to achieve.

I tried to reproduce this issue and I couldn't. I added a tag to the story, plus the filter, and the story rendered correctly when:

  • accessed directly via its iframe URL (like @JReinhold mentioned above)
  • accessed as part of an iframe like <iframe src="http://localhost:3000/iframe.html?the-rest-of-the-url.." />
  • referenced via a Story doc block in MDX
  • referenced via a Story doc block in MDX with inline={false} which makes it render inside of an iframe

IMO you could take a look into referencing your stories via the Story doc block, instead of iframes:
https://storybook.js.org/docs/api/doc-block-story

@vsMdulcio
Copy link

You can also setup the tags at the story level to look like this: tags: ['!dev'] according the docs here https://storybook.js.org/docs/writing-stories/tags, and it works.

@yuri-scarbaci-lenio
Copy link
Contributor

Hello,
Thanks for commenting back and trying to help further

I did try again using
"@storybook/react-vite": "~8.1.1"
(my previous tries where with the webpack bundler)

and given:
image
image
this is 100% behaving as I expected it to, which means:
1 - the story is not shown in the search results
now
image

before
image
2 - the story is not shown in the sidebar ever
now
image
before
image

3- the story hosting the iframe properly connects to the url and show it as expected
image

to be clear, I did not change the iframe src url, they where correct from the get go, the only change I did after your suggestions is that I am now using react-vite and latest storybook (which may imply this is not correctly working in some storybook combination, but given it works starting "~8.1.1" I don't think it's a big deal)

thanks a lot, this will help a lot with documenting microfront-end scenarios!

IMO you could take a look into referencing your stories via the Story doc block, instead of iframes:
https://storybook.js.org/docs/api/doc-block-story

The issue is in our scenarios we are purposely using the iframes because we specifically have to document how our components works in micro-front-end application that are built with iframes which like it or not is one of the current industry accepted way to build micro-front-ends portals and that from the design system standpoint has a pletora of specific challenges to address that are unique to this way of composing the final app

@shilman
Copy link
Member

shilman commented Jun 25, 2024

For anybody who's landing on this issue, here is the recommended way to hide stories from the sidebar:

https://storybook.js.org/docs/writing-stories/tags

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

Successfully merging a pull request may close this issue.