diff --git a/addons/docs/docs/recipes.md b/addons/docs/docs/recipes.md
index aa0b9512be29..5ffd73b06bb2 100644
--- a/addons/docs/docs/recipes.md
+++ b/addons/docs/docs/recipes.md
@@ -30,7 +30,7 @@ The only limitation is that your exported titles (CSF: `default.title`, MDX `Met
Perhaps you want to write your stories in CSF, but document them in MDX? Here's how to do that:
-**Button.stories.mdx**
+**Button.mdx**
```md
import { Story } from '@storybook/addon-docs/blocks';
@@ -51,18 +51,24 @@ And of course I can also embed arbitrary markdown & JSX in this file.
```js
import { Button } from './Button';
-import mdx from './Button.stories.mdx';
+import mdx from './Button.mdx';
export default {
title: 'Demo/Button',
parameters: {
- docs: mdx.parameters.docs,
+ docs: mdx,
},
};
export const basic = () => ;
```
+Note that in contrast to other examples, the MDX file suffix is `.mdx` rather than `.stories.mdx`. This key difference means that the file will be loaded with the default MDX loader rather than Storybook's CSF loader, which has several implications:
+
+1. You don't need to provide a `Meta` declaration.
+2. You can refer to existing stories (i.e. ``) but cannot define new stories (i.e. ``).
+3. The documentation gets exported as the default export (MDX default) rather than as a parameter hanging off the default export (CSF).
+
## Migrating from notes/info addons
If you're currently using the notes/info addons, you can upgrade to DocsPage [using slots](./docspage.md#docspage-slots). There are different ways to use each addon, so you can adapt this recipe according to your use case.
diff --git a/addons/docs/src/blocks/DocsContainer.tsx b/addons/docs/src/blocks/DocsContainer.tsx
index cca70a4886a6..f3a3c66ff6e0 100644
--- a/addons/docs/src/blocks/DocsContainer.tsx
+++ b/addons/docs/src/blocks/DocsContainer.tsx
@@ -9,7 +9,6 @@ import { DocsContextProps, DocsContext } from './DocsContext';
interface DocsContainerProps {
context: DocsContextProps;
- content: React.ElementType;
}
interface CodeOrSourceProps {
@@ -43,7 +42,7 @@ const defaultComponents = {
export const DocsContainer: React.FunctionComponent = ({
context,
- content: MDXContent,
+ children,
}) => {
const parameters = (context && context.parameters) || {};
const options = parameters.options || {};
@@ -55,9 +54,7 @@ export const DocsContainer: React.FunctionComponent = ({
-
-
-
+ {children}
diff --git a/addons/docs/src/blocks/DocsPage.tsx b/addons/docs/src/blocks/DocsPage.tsx
index f9010b0265c4..ad111727114c 100644
--- a/addons/docs/src/blocks/DocsPage.tsx
+++ b/addons/docs/src/blocks/DocsPage.tsx
@@ -3,8 +3,7 @@ import React from 'react';
import { parseKind } from '@storybook/router';
import { DocsPage as PureDocsPage, PropsTable, PropsTableProps } from '@storybook/components';
import { H2, H3 } from '@storybook/components/html';
-import { DocsContext, DocsContextProps } from './DocsContext';
-import { DocsContainer } from './DocsContainer';
+import { DocsContext } from './DocsContext';
import { Description, getDocgen } from './Description';
import { Story } from './Story';
import { Preview } from './Preview';
@@ -95,13 +94,13 @@ const DocsStory: React.FunctionComponent = ({
>
);
-const DocsPage: React.FunctionComponent = ({
- titleSlot,
- subtitleSlot,
- descriptionSlot,
- primarySlot,
- propsSlot,
- storiesSlot,
+export const DocsPage: React.FunctionComponent = ({
+ titleSlot = defaultTitleSlot,
+ subtitleSlot = defaultSubtitleSlot,
+ descriptionSlot = defaultDescriptionSlot,
+ primarySlot = defaultPrimarySlot,
+ propsSlot = defaultPropsSlot,
+ storiesSlot = defaultStoriesSlot,
}) => (
{context => {
@@ -130,35 +129,3 @@ const DocsPage: React.FunctionComponent = ({
}}
);
-
-interface DocsPageWrapperProps {
- context: DocsContextProps;
- titleSlot?: StringSlot;
- subtitleSlot?: StringSlot;
- descriptionSlot?: StringSlot;
- primarySlot?: StorySlot;
- propsSlot?: PropsSlot;
- storiesSlot?: StoriesSlot;
-}
-
-const DocsPageWrapper: React.FunctionComponent = ({
- context,
- titleSlot = defaultTitleSlot,
- subtitleSlot = defaultSubtitleSlot,
- descriptionSlot = defaultDescriptionSlot,
- primarySlot = defaultPrimarySlot,
- propsSlot = defaultPropsSlot,
- storiesSlot = defaultStoriesSlot,
-}) => (
- /* eslint-disable react/destructuring-assignment */
- (
-
- )}
- />
-);
-
-export { DocsPageWrapper as DocsPage };
diff --git a/addons/docs/src/frameworks/angular/config.js b/addons/docs/src/frameworks/angular/config.js
index 1c4f0ff0b166..2017a4bb6ad5 100644
--- a/addons/docs/src/frameworks/angular/config.js
+++ b/addons/docs/src/frameworks/angular/config.js
@@ -1,7 +1,8 @@
/* eslint-disable import/no-extraneous-dependencies */
import { addParameters } from '@storybook/angular';
-import { DocsPage } from '@storybook/addon-docs/blocks';
+import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
addParameters({
+ docsContainer: DocsContainer,
docs: DocsPage,
});
diff --git a/addons/docs/src/frameworks/html/config.js b/addons/docs/src/frameworks/html/config.js
index e309c872803e..9b7b52320cdb 100644
--- a/addons/docs/src/frameworks/html/config.js
+++ b/addons/docs/src/frameworks/html/config.js
@@ -1,7 +1,8 @@
/* eslint-disable import/no-extraneous-dependencies */
import { addParameters } from '@storybook/html';
-import { DocsPage } from '@storybook/addon-docs/blocks';
+import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
addParameters({
+ docsContainer: DocsContainer,
docs: DocsPage,
});
diff --git a/addons/docs/src/frameworks/react/config.js b/addons/docs/src/frameworks/react/config.js
index 0b0bcf5d69f4..69f35dc6db05 100644
--- a/addons/docs/src/frameworks/react/config.js
+++ b/addons/docs/src/frameworks/react/config.js
@@ -1,7 +1,8 @@
/* eslint-disable import/no-extraneous-dependencies */
import { addParameters } from '@storybook/react';
-import { DocsPage } from '@storybook/addon-docs/blocks';
+import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
addParameters({
+ docsContainer: DocsContainer,
docs: DocsPage,
});
diff --git a/addons/docs/src/frameworks/vue/config.js b/addons/docs/src/frameworks/vue/config.js
index 94889f73bea7..17584c29c593 100644
--- a/addons/docs/src/frameworks/vue/config.js
+++ b/addons/docs/src/frameworks/vue/config.js
@@ -1,7 +1,8 @@
/* eslint-disable import/no-extraneous-dependencies */
import { addParameters } from '@storybook/vue';
-import { DocsPage } from '@storybook/addon-docs/blocks';
+import { DocsPage, DocsContainer } from '@storybook/addon-docs/blocks';
addParameters({
+ docsContainer: DocsContainer,
docs: DocsPage,
});
diff --git a/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap b/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap
index f83d2bfa3515..fd74553dda9a 100644
--- a/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap
+++ b/addons/docs/src/mdx/__snapshots__/mdx-compiler-plugin.test.js.snap
@@ -72,12 +72,12 @@ const componentMeta = {
includeStories: ['one'],
};
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -125,12 +125,12 @@ storybookDocsOnly.story = { parameters: { docsOnly: true } };
const componentMeta = { title: 'docs-only', includeStories: ['storybookDocsOnly'] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -186,12 +186,12 @@ helloStory.story.parameters = { mdxSource: '' };
const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -268,12 +268,12 @@ const componentMeta = {
includeStories: ['componentNotes', 'storyNotes'],
};
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -344,12 +344,12 @@ const componentMeta = {
includeStories: ['helloButton', 'two'],
};
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -386,12 +386,12 @@ MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -435,12 +435,12 @@ text.story.parameters = { mdxSource: \\"'Plain text'\\" };
const componentMeta = { title: 'Text', includeStories: ['text'] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -501,12 +501,12 @@ wPunctuation.story.parameters = { mdxSource: ''
const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory', 'wPunctuation'] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -560,12 +560,12 @@ story0.story.parameters = {
const componentMeta = { includeStories: ['story0'] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -631,12 +631,12 @@ toStorybook.story.parameters = {
const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -673,12 +673,12 @@ MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
@@ -716,12 +716,12 @@ MDXContent.isMDXComponent = true;
const componentMeta = { includeStories: [] };
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => (
-
-);
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => (
+ {children}
+);
+componentMeta.parameters.docs = MDXContent;
export default componentMeta;
"
diff --git a/addons/docs/src/mdx/mdx-compiler-plugin.js b/addons/docs/src/mdx/mdx-compiler-plugin.js
index ce0eeb52e5e2..cacd34a1fd7c 100644
--- a/addons/docs/src/mdx/mdx-compiler-plugin.js
+++ b/addons/docs/src/mdx/mdx-compiler-plugin.js
@@ -163,10 +163,10 @@ function getExports(node, counter) {
// insert `mdxKind` into the context so that we can know what "kind" we're rendering into
// when we render ..., since this MDX can be attached to any `selectedKind`!
const wrapperJs = `
-const mdxKind = componentMeta.title || componentMeta.displayName;
-const WrappedMDXContent = ({ context }) => ;
+const mdxKind = componentMeta.title;
componentMeta.parameters = componentMeta.parameters || {};
-componentMeta.parameters.docs = WrappedMDXContent;
+componentMeta.parameters.docsContainer = ({ context, children }) => {children};
+componentMeta.parameters.docs = MDXContent;
`.trim();
function stringifyMeta(meta) {
diff --git a/examples/official-storybook/stories/addon-docs/mdx.stories.js b/examples/official-storybook/stories/addon-docs/mdx.stories.js
index caac0eb72601..48501bb9e820 100644
--- a/examples/official-storybook/stories/addon-docs/mdx.stories.js
+++ b/examples/official-storybook/stories/addon-docs/mdx.stories.js
@@ -1,8 +1,10 @@
import React from 'react';
+import { DocsContainer } from '@storybook/addon-docs/blocks';
import markdown from './markdown.stories.mdx';
export default {
title: 'Addons|Docs/mdx-in-story',
+ decorators: [storyFn => {storyFn()}],
};
// This renders the contents of the docs panel into story content
diff --git a/examples/official-storybook/stories/notes/notes.mdx b/examples/official-storybook/stories/notes/notes.mdx
index 48dc5de86eae..f030ec4a8932 100644
--- a/examples/official-storybook/stories/notes/notes.mdx
+++ b/examples/official-storybook/stories/notes/notes.mdx
@@ -1,3 +1,12 @@
+import { Props, Story } from '@storybook/addon-docs/blocks';
+import { Button } from '@storybook/react/demo';
+
# Welcome!
-Let's just write markdown without stories
+Let's write markdown without stories
+
+But we can still use doc blocks in our stories
+
+
+
+
diff --git a/lib/core/src/client/preview/start.js b/lib/core/src/client/preview/start.js
index cf81ebf25004..5fa69e7df0f7 100644
--- a/lib/core/src/client/preview/start.js
+++ b/lib/core/src/client/preview/start.js
@@ -217,9 +217,14 @@ export default function start(render, { decorateStory } = {}) {
// Given a cleaned up state, render the appropriate view mode
switch (viewMode) {
case 'docs': {
- const StoryDocs = (parameters && parameters.docs) || NoDocs;
+ const DocsContainer =
+ // eslint-disable-next-line react/prop-types
+ (parameters && parameters.docsContainer) || (({ children }) => <>{children}>);
+ const Docs = (parameters && parameters.docs) || NoDocs;
ReactDOM.render(
- ,
+
+
+ ,
document.getElementById('docs-root')
);
break;