There are certain rare scenarios where it becomes necessary to import a JavaScript script into a specific story view when working with Storybook.
Since I couldn’t find any solutions online, I’m publishing this article to address the needs of those who have asked similar unanswered questions.
I have also created a GitHub repository with a working demo for this resolution.
Let’s break this down step by step.
Locate your script"undefined" anchor link
For this example, I created a simple JavaScript file located at stories/scripts/custom-script.js
with the following content:
alert('Hello!')
Make the scripts folder available to Storybook"undefined" anchor link
Next, we need to configure Storybook to load the files from the scripts
folder.
To achieve this, simply add the staticDirs
field in your Storybook configuration, located at storybook/main.js
, specifying the path to your folder.
/** @type { import('@storybook/html-vite').StorybookConfig } */const config = { stories: ['../stories/**/*.mdx', '../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)'], addons: [ '@storybook/addon-essentials', '@chromatic-com/storybook', '@storybook/addon-interactions', ], framework: { name: '@storybook/html-vite', options: {}, }, staticDirs: ['../stories/scripts'],}export default config
Adding custom head scripts for component views"undefined" anchor link
In some cases, you may need to include custom JavaScript scripts for for all views of a specific component.
Simply, add the following decorator
in the default export.
export default { title: 'Example/Button', tags: ['autodocs'], render: ({ label, ...args }) => { // You can either use a function to create DOM element<a href="https://github.com/victor-lillo/storybook-custom-head-scripts-single-story/tree/main/stories/scripts" target="_blank" rel="noreferrer">`stories/scripts/custom-script.js`</a>s or use a plain html string! // return `<div>${label}</div>`; return createButton({ label, ...args }) }, argTypes: { backgroundColor: { control: 'color' }, label: { control: 'text' }, onClick: { action: 'onClick' }, primary: { control: 'boolean' }, size: { control: { type: 'select' }, options: ['small', 'medium', 'large'], }, }, // Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args args: { onClick: fn() }, // Dynamically inject head elements for this story decorators: [ (Story) => { const script = document.createElement('script') script.src = '/custom-script.js' script.type = 'module' document.head.appendChild(script)
return Story() }, ],}
export const Primary = { args: { primary: true, label: 'Button', },}
export const Secondary = { args: { label: 'Button', },}
Adding custom head scripts for a single story view"undefined" anchor link
Instead, there are times when we only need to add the script to a specific view of a component.
As in the previous example, add the decorator
, but this time into the specific view export.
export default { title: 'Example/Page', // ...}
export const LoggedOut = {}
export const LoggedIn = { // ...}
export const withScript = { // Dynamically inject head elements for this story decorators: [ (Story) => { const script = document.createElement('script') script.src = '/custom-script.js' script.type = 'module' document.head.appendChild(script)
return Story() }, ],}
I hope you found this article useful.
Happy coding! 🚀