Documenting Components

React Showroom generates documentations for your components based on type definition of your components, the comments on the type definitions, and markdown file.

Documenting Component Props

Declare your component props as usual in TypeScript:

src/components/button.tsx
import * as React from 'react';
export interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> {
variant: 'primary' | 'secondary';
fullWidth?: boolean;
rounded?: 'sm' | 'lg';
}
export const Button = ({
type = 'button',
variant,
fullWidth,
rounded,
style = {},
...props
}: ButtonProps) => {
return (
<button
{...props}
style={{
...style,
display: 'inline-flex',
gap: 8,
alignItems: 'center',
backgroundColor: variant === 'primary' ? 'red' : 'blue',
color: '#efefef',
padding: '8px 16px',
width: fullWidth ? '100%' : undefined,
borderRadius: rounded ? (rounded === 'lg' ? 16 : 4) : undefined,
}}
type={type}
/>
);
};
tsx

And the following will be generated:

http://localhost:6969

Button

NAMETYPEDEFAULTDESCRIPTION
variant"primary" | "secondary"Required
fullWidthboolean-
rounded"sm" | "lg"-

Comments for Component and Props

To provide more descriptions to the props and the comment itself, you can add JSDoc style comments.

src/components/button.tsx
import * as React from 'react';
export interface ButtonProps extends React.ComponentPropsWithoutRef<'button'> {
/**
* variant for the button
*/
variant: 'primary' | 'secondary';
/**
* specify if the button should takes up all the available horizontal space.
*/
fullWidth?: boolean;
/**
* controls the border radius.
*/
rounded?: 'sm' | 'lg';
}
/**
* `<Button />` component is a wrapper of `<button>` element.
*
* Unspecified props will be spreaded.
*/
export const ButtonWithComments = ({
type = 'button',
variant,
fullWidth,
rounded,
...props
}: ButtonProps) => {
return (
<button
{...props}
style={{
backgroundColor: variant === 'primary' ? 'red' : 'blue',
color: '#efefef',
padding: '8px 16px',
width: fullWidth ? '100%' : undefined,
borderRadius: rounded ? (rounded === 'lg' ? 16 : 4) : undefined,
}}
type={type}
/>
);
};
tsx

And the documentations will be reflected.

http://localhost:6969

ButtonWithComments

<Button /> component is a wrapper of <button> element.
Unspecified props will be spreaded.
NAMETYPEDEFAULTDESCRIPTION
variant"primary" | "secondary"Requiredvariant for the button
fullWidthboolean-specify if the button should takes up all the available horizontal space.
rounded"sm" | "lg"-controls the border radius.

JSDoc tags will be parsed and displayed as well.

src/components/button.tsx
import * as React from 'react';
export interface OldButtonProps
extends React.ComponentPropsWithoutRef<'button'> {
color: 'primary' | 'secondary';
}
/**
* @deprecated use `<Button />` instead.
*
* @version 1.0.0
* @see http://some-stackoverflow-question-that-i-copy-but-dont-understand.com
*/
export const OldButton = ({
type = 'button',
color,
...props
}: OldButtonProps) => {
return <button {...props} type={type} />;
};
tsx

will results in

http://localhost:6969

OldButton

deprecated: use `<Button />` instead.

version: 1.0.0

see: http://some-stackoverflow-question-that-i-copy-but-dont-understand.com

NAMETYPEDEFAULTDESCRIPTION
color"primary" | "secondary"Required

Show Usages with Markdown

To show usage examples for the component, create a .mdx file next to the component with the same name as the component file.

src/components/button.mdx
```tsx
<Button>Hello</Button>
```
## Using React Hooks
Example with states:
```tsx
import * as React from 'react';
const Example = () => {
const [on, setOn] = React.useState<boolean>(false);
return <Button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</Button>;
};
<Example />;
```
Add `frame` to render examples in iframe. This is very handy to see how the component is rendered in different screen size.
```tsx frame
<Button>Hello</Button>
```
Calling `console.log`, `console.info`, `console.warn`, `console.error` in the example will log the result in a separate panel.
```tsx frame
import * as React from 'react';
const Example = () => {
const [on, setOn] = React.useState<boolean>(false);
return (
<Button
onClick={() => {
console.log(`Changing`, { from: on, to: !on });
setOn(!on);
}}
>
{on ? 'On' : 'Off'}
</Button>
);
};
<Example />;
```
mdx

will produces the following output.

http://localhost:6969/
In this page

Button

NAMETYPEDEFAULTDESCRIPTION
variant"primary" | "secondary"Required
fullWidthboolean-
rounded"sm" | "lg"-

Using React Hooks

Example with states:

Add frame to render examples in iframe. This is very handy to see how the component is rendered in different screen size.

Calling console.log, console.info, console.warn, console.error in the example will log the result in a separate panel.

Open the hamburget menu and choose view as Designer to see the technical details hidden.

This is handy for non-technical audience (designer/business) to view the site.

Few things to take note:

  • You must tag the code block with tsx or jsx for it to become live example.
  • If the last expression in your code block is a JSX, that will be the displayed result of the example.
  • The component is automatically injected into the scope, so you doesn't need to import it.
  • React is automatically injected into the scope as well, but it's fine if you want to import it.

A few scenarios for code blocks:

src/components/button.mdx
Manually call `render` if you want to add some operations before rendering the output.
```tsx
const wait = (ms: number) => new Promise((fulfill) => setTimeout(fulfill, ms));
wait(1000).then(() => render(<Button>Delayed</Button>));
```
Importing third party libraries work as well as long as they are installed in your project.
If user add additional import statement in live editor, they will be loaded from [Skypack](https://www.skypack.dev/) on the fly.
```tsx
import { useForm } from 'react-hook-form';
const FormExample = () => {
const {
register,
handleSubmit,
watch,
formState: { errors },
} = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
<div className="space-x-2">
<label htmlFor="firstName">First Name</label>
<input type="text" defaultValue="John" {...register('firstName')} />
</div>
<div className="space-x-2">
<label htmlFor="lastName">Last Name</label>
<input type="text" {...register('lastName', { required: true })} />
{errors.lastName && <span>This field is required</span>}
</div>
<Button type="submit">Submit</Button>
</form>
);
};
<FormExample />;
```
Use `fileName` modifier to add a file name at the top of the code block.
```tsx fileName="code.tsx"
import * as React from 'react';
const Example = () => {
const [on, setOn] = React.useState<boolean>(false);
return <Button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</Button>;
};
<Example />;
```
For code blocks with `frame`, by default we will adjust the given height based on the rendered content.
You can overwrite the height (fixed), initial height (initial iframe height while waiting the content to be rendered), and initial width using `height`, `initialHeight`, and `initialWidth` modifiers respectively.
```tsx frame height=100
<Button>Height: 100</Button>
```
```tsx frame initialHeight=48
<Button>Initial Height: 48</Button>
```
```tsx frame initialWidth=400
<Button>Initial Width: 400</Button>
```
Use `noEditor` modifier to show only the output result.
```tsx noEditor
import * as React from 'react';
const Example = () => {
const [on, setOn] = React.useState<boolean>(false);
return <Button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</Button>;
};
<Example />;
```
Use `static` modifier to show static code.
```tsx static
<Button>Hello</Button>
```
For static code blocks, you can use `highlights` to highlight specific lines.
```tsx static highlights={3-7}
import * as React from 'react';
const Example = () => {
const [on, setOn] = React.useState<boolean>(false);
return <Button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</Button>;
};
<Example />;
```
mdx

And the result:

http://localhost:6969/

Button

NAMETYPEDEFAULTDESCRIPTION
variant"primary" | "secondary"Required
fullWidthboolean-
rounded"sm" | "lg"-

Manually call render if you want to add some operations before rendering the output.

Importing third party libraries work as well as long as they are installed in your project.

If user add additional import statement in live editor, they will be loaded from Skypack on the fly.

Use fileName modifier to add a file name at the top of the code block.

code.tsx

For code blocks with frame, by default we will adjust the given height based on the rendered content.

You can overwrite the height (fixed), initial height (initial iframe height while waiting the content to be rendered), and initial width using height, initialHeight, and initialWidth modifiers respectively.

Use noEditor modifier to show only the output result.

Use static modifier to show static code.

<Button>Hello</Button>
tsx

For static code blocks, you can use highlights to highlight specific lines.

import * as React from 'react';
const Example = () => {
const [on, setOn] = React.useState<boolean>(false);
return <Button onClick={() => setOn(!on)}>{on ? 'On' : 'Off'}</Button>;
};
<Example />;
tsx

Show Different Variants

A common use case is to show different variants of the component side-by-side so they can be compared visually.

You can, of course, render the component by passing different props to it in an example to do that.

However, you need to maintain the example so any changes to the props will be reflected in the example.

Another options is to use the useUnionProps custom hook (available in react-showroom/client), which provide the variants (parsed from the props type definition) as options to your examples.

src/components/button.mdx
```tsx
import { useUnionProps } from 'react-showroom/client';
const Variants = () => {
const variantOptions = useUnionProps('variant');
const roundedOptions = useUnionProps('rounded');
return (
<div>
{variantOptions.map((vOption) => (
<div
style={{
display: 'flex',
gap: '1rem',
marginBottom: '0.5rem',
alignItems: 'center',
}}
key={vOption.value}
>
<div>{vOption.label}</div>
{roundedOptions.map((rOption) => (
<Button
variant={vOption.value}
rounded={rOption.value}
key={rOption.value}
>
rounded="{rOption.label}"
</Button>
))}
</div>
))}
</div>
);
};
<Variants />;
```
mdx
http://localhost:6969/

Button

NAMETYPEDEFAULTDESCRIPTION
variant"primary" | "secondary"Required
fullWidthboolean-
rounded"sm" | "lg"-
primary
secondary

Collaboration Tips

React Showroom is developed with helping collaborations in mind, and the following are some tips to use it effectively.

Use Standalone View to Share Particular Example/Snapshot

All examples will generates a standalone view (which can be opened with the "Standalone" button at bottom right).

  • The standalone view has its own URL that you can share with others.
  • In the standalone view, you can update the code or update the props (for Component Playground) and those changes will be persisted in the URL.
  • You can also add comment on particular point of the example, and those will be persisted in the URL as well. For example, try open this link.

Use the Accessibility Check Result to Discuss Accessibility Issues

The accessibility check result (powered by axe-core) is a good starting point to discuss about accessibility issues of your components/designs.

You can highlight the elements in the example by checking the "Highlight" checkbox.