<img src="images/logo.png?raw=true#gh-light-mode-only" alt="Playroom" title="Playroom" width="292" height="50" />
<img src="images/logo-inverted.png?raw=true#gh-dark-mode-only" alt="Playroom" title="Playroom" width="292" height="50" />

[![npm](https://img.shields.io/npm/v/playroom.svg?style=for-the-badge)](https://www.npmjs.com/package/playroom) [![Build Status](https://img.shields.io/github/actions/workflow/status/seek-oss/playroom/validate.yml?branch=master&style=for-the-badge)](https://github.com/seek-oss/playroom/actions?query=workflow%3AValidate+branch%3Amaster)

---

<img src="images/demo.gif?raw=true" alt="Playroom Demo" title="Playroom Demo" />

Simultaneously design across a variety of themes and screen sizes, powered by JSX and your own component library.

Playroom allows you to create a zero-install code-oriented design environment, built into a standalone bundle that can be deployed alongside your existing design system documentation.

- Iterate on your designs in the final medium.
- Create quick mock-ups and interactive prototypes with real code.
- Exercise and evaluate the flexibility of your design system.
- Share your work with others by simply copying the URL.

## Demos

[Braid Design System](https://seek-oss.github.io/braid-design-system/playroom/#?code=N4Igxg9gJgpiBcIA8BBANjATgFwATYgDsYBeAHRAEtCAzCCgPiQBUYAPbBgdRjUgFsY%2BCLgAKaAIYBPTBAj8AhEgD0rDk2XosnEABoQ2ABYxBAZwQBtEBIAOEsCAC6%2BgO6UoR8-AsB2AGwAHI4AvkA) (Themed)

[Bumbag](https://bumbag.style/playroom/)

[Overdrive](http://overdrive.autoguru.io/playroom/#?code=N4Igxg9gJgpiBcIA8AhCAPABAIwwZQAsBDKCAdwF4AdEAZhswAcSoBLAOwHMLgBtG+iAA0mGgDYaAXQC+APirtMmJHgAuRMAGtMAZ2ZgO3cTXmKlygCox0qgMIR26jjABOmAjBKGeSABKe2LllfVkxVDxcYTEBeDcBpHaQAen8vILkFc3MkKxtZAHUYABtIAFso1Qgwj0wAQQBXcoBxWpdazFgdVk5FHQBPHVUYYswAWkwAeQA3VygXVimAQkTs1VMMpes7Byd2V1N0zOWASXZGeqYCjRgCCALYF2oQX3JMIkjMHohagH4GBNXlBJqDSaUyJNDoUwgaRAA)

[Cubes](https://cubes.trampoline.cx/) (Themed)

[Mesh Design System](https://www.meshdesignsystem.com/playroom/) (Themed)

[Mística Design System](https://mistica-web.vercel.app/playroom) (Themed)

[Shopify Polaris](https://polaris.shopify.com/sandbox?code=N4Igxg9gJgpiBcIA8BhAhgJygHQHYAJ8BnGSXKTATwDEIIAXGDAQTHoEsJciBeYAbWBlGuevHwByACLsiAW1lEJAXwC6yvIQAOGdnKq0GTVhy58hXEWMkBRAB5aIGevgBKMR85UbcAPk34qJhQAHQAEjBosBj4aGyc3HyC%2BMIwouISACoMaAA2%2BADKeTBK%2BGrK%2BBz0uTA82CBFNUT1-gSEgQAKEI4AbkwB7bHxfXwAZnkkPoOEcRw9aPROfAPTSABCAK70iwRQsmC5EEQbGDD4Wrlo7H4r0-gAauwwAO6Fxc1td0gA9JvbXK07lNplwUIcSHwABQASnwPF8%2BGAymBhEBqxMCQAMrIXOxGHJeAILKI0tYJABxDBHIhvJoqAA0iNS6UkADkYC5GiUVOp8N80YQfl1ekw0T90FhwpFomKJaECqRTDdPoFMjA7PQUJYrrhRbd8ABNCAbFJoAgbEjEd74U6eeg0xbEGBna6jJz6JWxABGxpclGNMTAFsWciYREAmAT6pzRGletAkKD4LgpXSMXRoYgbMAAC1iNKI1ogfRiHFDjK9lBS2bNutyjKc%2BAr%2BqI9DQo1GIRWPzVGq1oh1era4uCIQV8QBASCkrHnqqNTqIGyrfyXJpa1OaAA1lAIM9cC0u%2B4iAGwDBsS39adjydT6y0KHzERrgBzDaXDAZAs1CSMi4nPKfu83j6niMAEkk%2BqEMAkHtF%2BJQZAA8lgYY-jBMxyMaLISAAqgUUgACQAAwhIRhGoSqdwnLkGS2k49rfNGKH0jByjMRR7TQexgxwUQGTuPQJzcORdyDPemFkgAtLhBEAEwAKzEaRwkiYQVE0R4dFEN8pwCRgQlsSprH6uol5pNEACS%2BJQqBciwvCiIwWQLaIjxjJiRsoiMlRFQ8PgNkANwwTpgn4JCaGBEeJ5njiISWWB4WqRguR8N5CVDKeRBPl67C5HilCYmgXowMlwAAAaPC8tIlPgboxPhwA8copUoip%2BACq1SAFK2YCbu1rWBF1cSbrF%2BI1TluS%2BA17zKD8g09SNYF9R1c3DXFciTe5ogzd8K0LetaWzd1vXhT8kU3tFLZ7UthDQoF7HIvq-KTt8cqjoqCSyiOM4JJUeLzvUUiRMMCwwImtHOM0ICZl6UAbKD7VIOe9BLYjMVrb4HRoP6WxED8SNXfqqOXejS55FVa6Vig1a4LWeNo-iCPfEjYovV970TkOr3fcmc61PUrJGAeKpID2mratcg53Jk2ZnDxNoaRDsSnLE8w5YVNRJrguSVuwoz4NjMQtk4Lo0jzMuFNm3S65Q%2BoXGaSYxNm7DPjLGCdsL3yi32rYSxgLNc%2BzyrDlgvggPSID0DLoZEAg-AgIcYDFPAaQgKo4fPOwUCRzH8D8OoQA)

[Agriculture Design System](https://design-system.agriculture.gov.au/playroom/#?code=N4Igxg9gJgpiBcIA8AhCAPABFAhgJwGsA%2BAHQDtNMkAJGHWPTAIxzAIHM8IBXMqAXhIgm0AJ4BBADYAXIZkkR2EfsCQAZRREwB6IgF9MACzpQAlmXaCQAUXQAHCHmmYAyjDwA3U2Bhzd5SiQAWRxzADkcDwDKTFNpGABbAGcVAG1geRwmGEl4TCFqCATfEAAaIzwYADM8oW05PQBdPWjKJJhIPnxRAEl45LSMySyc2pAXU3YKcyFymD5rSUT56TykcQ8caXwezp0iTCaWin3yJG00dFIyJAAFHHYYAGEIMni3zBwUoQTQsiFroFblx2oCYkhDABGIj3R5GEzmdjnKFgwJ2VExDSVBKxOxJbg4qAQBSMJJxT7FaTlTrtMDxaTcRj0Ux2UxJMCIzA5OIAOkwtxySzeMCSAEduDBPrITjFPngwNwuUtTFV5lByps8KZuEkuWRTDiyK85srVXxMPqmIY%2BQBFbhs8WS1iZDn6nBK3mtGIAeXlpkwmu1urIWwgjswdnmW1MTB1XOcvymbOwybs%2BAZWpWmASr3iSXKIfZMAzXsoWrMCskcYSOr5PWFj1JPiWWrFEql8km3GGmH6DkYORgKrVfIAaiLpDHuwTSwHidxpGmqdhiY4uYq8AvNziaTBxVtypIY%2B4tAArHXSLTDV2md2XpyOcqmKCzwNx%2B-3z7CzBk5w4SkWmykh8uI8x0BQWzYPaKb-nyTx4F8nyduw3bujgs44N%2BOBHvuOLXuYt58gAqs4RIkpguHlJwkTPu6MCKlA0Himy5Q5ksSSTr4MoxPhboriSfIAGI6j4LrVqY5R2IY%2BDFgh2bEhOpiSh%2Ba70eUVQEbGSSzrxt6dtkXA8l65zosZpncZQLg6pGfBsu0mCqtw7C3s4eCGK8Cq6omIZKkOZpQJ8OHcLBmBBI4TD%2BvRbI5gFMDoLOnSbJIR66l4HjuHJg7DnwfJhN2ww4ulkgOZpcZHgZEB8iEHRRrqSxaO0CSlAlry0vSjI-uS-7Fri%2BKFTk1JFDFWj9tIk6frhuX5f%2B%2BknrOZDTdSjL4rqd6MqyurFuU00JJAeCRowCgiE4yaUrWmBSKYuGBVdwUJLOSTQNhIrZs9%2BL0DgfK3NJ7TJXGv4Uj15UnpgC4WtNEaONsmCOCGlR1v8Fkes4Sx0jqT6sN2yY9R486LpBMCPMufZrrDMlciCCPxHgjE4sWs6-OxwW4A53WrWAX7xL1BIRlqCTJuYrPcByWl8lZSQ2WYST2Y9uDsQzxZxsxqXdnYC5bJKiXYSlVXhf6nQoZKqMMptROvdL7oaZaOo6cLJtfYKKwiuGfZxox-pFZ8dtrjte0HUZ3EmWC5zAhAoJnNosLPLmKzXKgGDYPgxDREggkQBA1PMKwHBcLwAhCCIUASDIALGSGHhyreAC0wzZJIVhVOn1Ol0j6jmAQahstKsqyu5WoAF65ths6UEeZAECkwCpCPMQZIYlQ1PkIAAMSzJkddjIUxQNM1SOynPC9jKvZTr6MS8ACruMkX4BZ0ZiTq1O8z5QB-VEfa%2B12fQjAqYmxgKIkMjz-yfnvWeFQ35L2PoeEYuQl7iEwJUbWACFAWE7OPXscQlggJ7jEZos5-CB20OXYO2g04Z3cHHC4GBrggD0EAA)

Send us a PR if you'd like to be in this list!

## Getting Started

```bash
$ npm install --save-dev playroom
```

Add the following scripts to your `package.json`:

```json
{
  "scripts": {
    "playroom:start": "playroom start",
    "playroom:build": "playroom build"
  }
}
```

Add a `playroom.config.js` file to the root of your project:

```js
module.exports = {
  components: './src/components',
  outputPath: './dist/playroom',

  // Optional:
  title: 'My Awesome Library',
  themes: './src/themes',
  snippets: './playroom/snippets.js',
  frameComponent: './playroom/FrameComponent.js',
  scope: './playroom/useScope.js',
  widths: [320, 768, 1024],
  port: 9000,
  openBrowser: true,
  paramType: 'search', // default is 'hash'
  exampleCode: `
    <Button>
      Hello World!
    </Button>
  `,
  baseUrl: '/playroom/',
  webpackConfig: () => ({
    // Custom webpack config goes here...
  }),
  iframeSandbox: 'allow-scripts',
  defaultVisibleWidths: [
    // subset of widths to display on first load
  ],
  defaultVisibleThemes: [
    // subset of themes to display on first load
  ],
};
```

_Note: `port` and `openBrowser` options will be set to `9000` and `true` (respectively) by default whenever they are omitted from the config above._

Your `components` file is expected to export a single object or a series of named exports. For example:

```js
export { default as Text } from '../Text'; // Re-exporting a default export
export { Button } from '../Button'; // Re-exporting a named export
// etc...
```

The `iframeSandbox` option can be used to set the [`sandbox` attribute](https://www.html5rocks.com/en/tutorials/security/sandboxed-iframes/) on Playroom's iframe. A minimum of `allow-scripts` is required for Playroom to work.

Now that your project is configured, you can start a local development server:

```bash
$ npm run playroom:start
```

To build your assets for production:

```bash
$ npm run playroom:build
```

## Snippets

Playroom allows you to quickly insert predefined snippets of code, providing live previews across themes and viewports as you navigate the list. These snippets can be configured via a `snippets` file that looks like this:

```js
export default [
  {
    group: 'Button',
    name: 'Strong',
    code: `
      <Button weight="strong">
        Button
      </Button>
    `,
  },
  // etc...
];
```

## Custom Frame Component

If your components need to be nested within custom provider components, you can provide a custom React component file via the `frameComponent` option, which is a path to a file that exports a component. For example, if your component library has multiple themes:

```js
import React from 'react';
import { ThemeProvider } from '../path/to/your/theming-system';

export default function FrameComponent({ theme, children }) {
  return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
```

## Custom Scope

You can provide extra variables within the scope of your JSX via the `scope` option, which is a path to a file that exports a `useScope` Hook that returns a scope object. For example, if you wanted to expose a context-based `theme` variable to consumers of your Playroom:

```js
import { useTheme } from '../path/to/your/theming-system';

export default function useScope() {
  return {
    theme: useTheme(),
  };
```

## Theme Support

If your component library has multiple themes, you can customise Playroom to render every theme simultaneously via the `themes` configuration option.

Similar to your `components` file, your `themes` file is expected to export a single object or a series of named exports. For example:

```js
export { themeA } from './themeA';
export { themeB } from './themeB';
// etc...
```

## TypeScript Support

If a `tsconfig.json` file is present in your project, static prop types are parsed using [react-docgen-typescript](https://github.com/styleguidist/react-docgen-typescript) to provide better autocompletion in the Playroom editor.

**By default, all `.ts` and `.tsx` files in the current working directory are included, excluding `node_modules`.**

If you need to customise this behaviour, you can provide a `typeScriptFiles` option in `playroom.config.js`, which is an array of globs.

```js
module.exports = {
  // ...
  typeScriptFiles: ['src/components/**/*.{ts,tsx}', '!**/node_modules'],
};
```

If you need to customise the [parser options](https://github.com/styleguidist/react-docgen-typescript#options), you can provide a `reactDocgenTypescriptConfig` option in `playroom.config.js`.

For example:

```js
module.exports = {
  // ...
  reactDocgenTypescriptConfig: {
    propFilter: (prop, component) => {
      // ...
    },
  },
};
```

## ESM Support

Playroom supports loading [ESM](https://nodejs.org/api/esm.html#introduction) configuration files. By default, Playroom will look for a playroom config file with either a `.js`, `.mjs` or `.cjs` file extension.

## Storybook Integration

If you are interested in integrating Playroom into Storybook, check out [storybook-addon-playroom](https://github.com/rbardini/storybook-addon-playroom).

## License

MIT.
