diff --git a/.storybook/preview.js b/.storybook/preview.js
index 4305b6bebe269..fef17237e88a9 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -10,4 +10,9 @@ export const parameters = {
disable: true,
expanded: true,
},
+ docs: {
+ source: {
+ excludeDecorators: true,
+ },
+ },
};
diff --git a/change/@fluentui-react-button-2b550638-96d1-40ea-9b3f-94bd0ecc1d89.json b/change/@fluentui-react-button-2b550638-96d1-40ea-9b3f-94bd0ecc1d89.json
new file mode 100644
index 0000000000000..f55f555937b04
--- /dev/null
+++ b/change/@fluentui-react-button-2b550638-96d1-40ea-9b3f-94bd0ecc1d89.json
@@ -0,0 +1,7 @@
+{
+ "type": "none",
+ "comment": "Button docs",
+ "packageName": "@fluentui/react-button",
+ "email": "peter@draxler.ml",
+ "dependentChangeType": "none"
+}
diff --git a/packages/react-button/.storybook/preview.js b/packages/react-button/.storybook/preview.js
index b52409294c330..75f5ad3840b32 100644
--- a/packages/react-button/.storybook/preview.js
+++ b/packages/react-button/.storybook/preview.js
@@ -1,3 +1,4 @@
import * as rootPreview from '../../../.storybook/preview';
export const decorators = [...rootPreview.decorators];
+export const parameters = { ...rootPreview.parameters };
diff --git a/packages/react-button/src/Button.stories.tsx b/packages/react-button/src/Button.stories.tsx
deleted file mode 100644
index d1c6754cf9e7d..0000000000000
--- a/packages/react-button/src/Button.stories.tsx
+++ /dev/null
@@ -1,118 +0,0 @@
-import * as React from 'react';
-import { Button, ButtonProps } from './Button';
-import { Playground } from './Playground.stories';
-import { PlaygroundProps } from './Playground.types.stories';
-import { buttonBaseProps } from './buttonBaseProps.stories';
-
-// TODO: this is here while waiting for react-icons to merge
-const SVGIcon = () => (
-
-
-
-
-
-);
-
-export const Default = () => ;
-
-//
-// Anatomy & Layout
-//
-
-export const TextOnly = () => Text ;
-export const TextOnlyLong = () => Text truncates after it hits the max width token value ;
-
-export const IconWithText = () => (
- <>
- }>Text
- } iconPosition="after">
- Text
-
- >
-);
-
-export const IconOnly = () => } />;
-
-//
-// Size
-//
-const SizeExample = ({ size }: { size?: ButtonProps['size'] }) => (
- <>
-
{size || '(default)'}
- Text
- }>
- Text
-
- } />
- >
-);
-
-export const Size = () => (
- <>
-
-
-
- >
-);
-
-//
-// Appearance
-//
-const AppearanceExample = (props: ButtonProps) => (
- <>
- } />
-
- Text
- }>
- Text
-
- } iconPosition="after">
- Text
-
- >
-);
-
-export const Primary = () => ;
-
-//
-// States
-//
-export const Disabled = () => (
- <>
- }>
- Default disabled
-
- }>
- Primary disabled
-
- >
-);
-
-const buttonProps: PlaygroundProps['sections'] = [
- { sectionName: 'Button props', propList: buttonBaseProps },
-];
-
-export const ButtonPlayground = () => (
-
-
-
-);
-
-export default {
- title: 'Components/Button',
- component: Button,
-};
diff --git a/packages/react-button/src/components/Button/Button.stories.tsx b/packages/react-button/src/components/Button/Button.stories.tsx
new file mode 100644
index 0000000000000..0d6a4f1cf4a4b
--- /dev/null
+++ b/packages/react-button/src/components/Button/Button.stories.tsx
@@ -0,0 +1,184 @@
+import * as React from 'react';
+import { Button, ButtonProps } from '../../Button';
+import { Meta } from '@storybook/react';
+import { CalendarMonth24Regular } from '@fluentui/react-icons';
+import descriptionMd from './ButtonDescription.md';
+import bestPracticesMd from './ButtonBestPractices.md';
+
+export const Default = (props: ButtonProps) => Button ;
+
+export const Emphasis = () => (
+ <>
+ Primary button
+ Default button
+ Outline button
+ Subtle button
+ Transparent button
+ >
+);
+Emphasis.parameters = {
+ docs: {
+ description: {
+ story:
+ '- `primary` button is used for the most important action on the page or in a view\n' +
+ '- `default` button is used for subordinate actions\n' +
+ '- `outline` has no background styling and is emphasized through the styling of its content and borders\n' +
+ '- `transparent` has no background or border styling and is just emphasized through its content styling\n' +
+ '- `subtle` button blends into its background and becomes less emphasized\n',
+ },
+ },
+};
+
+export const ButtonWithIcon = () => (
+ <>
+ }>Text
+ } iconPosition="after">
+ Text
+
+ } />
+ >
+);
+ButtonWithIcon.parameters = {
+ docs: {
+ description: {
+ story:
+ 'Button has an `icon` slot that, if specified, renders an icon either `before` or `after` the children, ' +
+ 'as specified by the `iconPosition` prop.',
+ },
+ },
+};
+
+export const CircularButton = () => (
+ <>
+ Button
+ } />
+ } />
+ } />
+ >
+);
+CircularButton.parameters = {
+ docs: {
+ description: {
+ story: 'A button can have completely rounded corners.',
+ },
+ },
+};
+
+export const ButtonSize = () => {
+ const groupStyles: React.CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: '0.5em' };
+ const headerStyles: React.CSSProperties = { width: '100%', margin: 0 };
+ return (
+ <>
+
+
small
+ Text
+ }>
+ Text
+
+ } />
+
+
+
medium
+ Text
+ }>Text
+ } />
+
+
+
large
+ Text
+ }>
+ Text
+
+ } />
+
+ >
+ );
+};
+ButtonSize.parameters = {
+ docs: {
+ description: {
+ story: 'A button supports `small`, `medium` and `large` size. Default size is `medium`.',
+ },
+ },
+};
+
+export const BlockButton = () => (
+ <>
+ Block button
+ >
+);
+BlockButton.parameters = {
+ docs: {
+ description: {
+ story: 'A button can fill the width of its container.',
+ },
+ },
+};
+
+export const DisabledButton = () => {
+ const groupStyles: React.CSSProperties = { display: 'flex', flexWrap: 'wrap', gap: '0.5em' };
+
+ return (
+ <>
+
+ Default
+ Disabled
+ Disabled focusable
+
+
+ }>
+ Primary
+
+ }>
+ Primary disabled
+
+
+ Primary disabled focusable
+
+
+ >
+ );
+};
+DisabledButton.parameters = {
+ docs: {
+ description: {
+ story: `A button can be \`disabled\` or \`disabledFocusable\`.
+ \`disabledFocusable\` is used in scenarios where it is important to keep a consistent tab order
+ for screen reader and keyboard users. The primary example of this pattern is when
+ the disabled button is in a menu or a commandbar and is seldom used for standalone buttons.`,
+ },
+ },
+};
+
+export const ButtonWithLongText = () => (
+ <>
+ Text
+ Text truncates after it hits the max width token value
+ >
+);
+ButtonWithLongText.parameters = {
+ docs: {
+ description: {
+ story: 'Text truncates after it hits the max width theme token value.',
+ },
+ },
+};
+
+export default {
+ title: 'Components/Button',
+ component: Button,
+ parameters: {
+ docs: {
+ description: {
+ component: [descriptionMd, bestPracticesMd].join('\n'),
+ },
+ },
+ },
+ decorators: [
+ Story => (
+
+
+
+ ),
+ ],
+} as Meta;
diff --git a/packages/react-button/src/components/Button/Button.tsx b/packages/react-button/src/components/Button/Button.tsx
index d71f9f2921ee3..157d95f9d99f5 100644
--- a/packages/react-button/src/components/Button/Button.tsx
+++ b/packages/react-button/src/components/Button/Button.tsx
@@ -5,8 +5,7 @@ import { renderButton } from './renderButton';
import { useButtonStyles } from './useButtonStyles';
/**
- * Define a styled Button, using the `useButton` hook.
- * {@docCategory Button}
+ * Buttons give people a way to trigger an action.
*/
export const Button: React.FunctionComponent> = React.forwardRef<
HTMLElement,
@@ -18,5 +17,4 @@ export const Button: React.FunctionComponent