- Setup: Getting started · Requirements · Config · Compilation · Webpack · Snowpack
- Usage: Fixtures · Decorators · Mocks · Control panel · UI plugins · Static export · React Native · Server-side APIs
- FAQ: Create React App · Next.js · Troubleshooting · Where's my old Cosmos? · Roadmap
The example package is a useful complement to this guide.
1. Install React Cosmos
# Using npm
npm i --D react-cosmos
# or Yarn
yarn add --dev react-cosmos
Please see Compilation to make sure you installed all necessary dependencies.
2. Add package.json scripts
"scripts": {
+ "cosmos": "cosmos",
+ "cosmos:export": "cosmos-export"
}
3. Start React Cosmos
# Using npm
npm run cosmos
# or Yarn
yarn cosmos
You may also run
npx react-cosmos
in your project without installing any deps.
4. Create your first fixture
Choose a simple component to get started.
// Hello.jsx
import React from 'react';
export function Hello({ greeting, name }) {
return <h1>{greeting}, {name}!</h1>;
}
Create a .fixture
file. You can customize this convention later.
Fixture files contain a default export, which can be a React Component or any React Node.
// Hello.fixture.jsx
import React from 'react';
import { Hello } from '../Hello';
export default <Hello greeting="Aloha" name="Alexa" />;
The hello
fixture will show up in your React Cosmos UI and will render when you select it.
5. Build amazing user interfaces
You've taken the first step towards designing reusable components. You can now prototype, test and interate on components in isolation. Use this to your advantage!
Something wrong? Don't hesitate to create a GitHub issue (be helpful and include details) and to join us on Slack.
The only hard requirements are React 16.8 and Node 10 (or newer).
React Cosmos works best with webpack 4. It takes extra effort to make it work with other bundlers, but it's not as scary as it might seem. Don’t be afraid to ask for support.
Browserify and Parcel examples are available for Cosmos Classic. Props to whoever adapts them to React Cosmos 5!
No config is required to start. If you have custom needs or would like to convert a Cosmos Classic config, here's what you need to know.
The React Cosmos config is a JSON file, so it can only host serializable values. This design decision is meant to discourage complex configuration, make it easy to embed config options into the UI, and enable visual config management in the future.
By default, Cosmos reads cosmos.config.json
from your root directory. You can pass a --config
CLI arg for a custom config path.
Most Cosmos Classic config options are still supported in the new JSON format. Let me know if you need old config options that no longer work.
The best way to learn about the available options in the Cosmos config is to use config.schema.json.
The schema is human readable, but you can also enhance your config with autocomplete in code editors like VS Code.
{
"$schema": "http://json.schemastore.org/cosmos-config"
// your options...
}
And if you use VS Code you can map the Cosmos config schema globally by extending your user settings.
"json.schemas": [
{
"fileMatch": ["cosmos.config.json"],
"url": "http://json.schemastore.org/cosmos-config"
}
]
Alternatively, you can reference the local Cosmos config schema in your workspace configuration.
"json.schemas": [
{
"fileMatch": ["cosmos.config.json"],
"url": "./node_modules/react-cosmos/config.schema.json"
}
]
How you compile your code is 100% your business. React Cosmos jumps through hoops to compile your code using your existing build pipeline, but it doesn't install any additional dependencies that your setup requires to compile your code.
React Cosmos compiles your code using the build dependencies already installed in your project.
Unless you use a framework like Create React App or Next.js, you need to install build dependencies yourself. This includes stuff like Babel, TypeScript, webpack loaders, html-webpack-plugin, etc.
Here is a common list of packages required to build React with webpack and Babel:
@babel/core @babel/preset-env @babel/preset-react babel-loader style-loader css-loader html-webpack-plugin@4
And unless you use a framework that does it under the hood, create a .babelrc
(or similar) config in your project root.
{
"presets": ["@babel/env", "@babel/react"]
}
Configuring webpack is the least romantic aspect of the Cosmos setup. Luckily, you only do it once. Depending on your setup, one of the following options will work for you.
In many cases Cosmos manages to get webpack working without human intervention. Try running Cosmos as is first.
Probably the most common scenario. Most of us end up with a hairy webpack config sooner or later. Use the webpack.configPath
setting to point to an existing webpack config.
{
"webpack": {
"configPath": "./webpack.config.js"
}
}
You can also point to a module inside a dependency, like in the Create React App example.
Overriding the webpack config gives you complete control. Use the webpack.overridePath
setting to point to a module that customizes the webpack config used by Cosmos.
{
"webpack": {
"overridePath": "./webpack.override.js"
}
}
The override function receives a base webpack config — the default one generated by Cosmos or a custom one loaded from webpack.configPath
. Extend the input config and return the result.
// webpack.override.js
module.exports = (webpackConfig, env) => {
return { ...webpackConfig /* do your thing */ };
};
Cosmos overwrites output.filename
in the webpack config to [name].js
by default. Due to caching, this isn't ideal when generating static exports via cosmos-export
command. Use the webpack.includeHashInOutputFilename
setting to change the filename template to [name].[contenthash].js
.
{
"webpack": {
"includeHashInOutputFilename": true
}
}
Fixture files contain a default export, which can be a React Component or any React Node.
React
must be imported in every fixture file.
The file paths of your fixture files (relative to your project root) are used to create a tree view explorer in the React Cosmos UI.
Think of Node fixtures as the return value of a function component, or the first argument to
React.render
.
// Button.fixture.jsx
export default <Button disabled>Click me</Button>;
Component fixtures are just function components with no props. They enable using Hooks inside fixtures, which is powerful for simulating state with stateless components.
// CounterButton.fixture.jsx
export default () => {
const [count, setCount] = React.useState(0);
return <CounterButton count={count} increment={() => setCount(count + 1)} />;
};
A fixture file can also export multiple fixtures if the default export is an object.
// Button.fixture.jsx
export default {
primary: <PrimaryButton>Click me</PrimaryButton>,
primaryDisabled: <PrimaryButton disabled>Click me</PrimaryButton>,
secondary: <SecondaryButton>Click me</SecondaryButton>,
secondaryDisabled: <SecondaryButton disabled>Click me</SecondaryButton>,
};
The object property names will show up as fixture names in the Cosmos UI.
See this comment for the reasoning behind this solution (vs named exports).
Two options:
- End fixture file names with
.fixture.{js,jsx,ts,tsx}
- Put fixture files inside
__fixtures__
Examples:
blankState.fixture.jsx
__fixtures__/blankState.jsx
File name conventions can be configured using the
fixturesDir
andfixtureFileSuffix
options.
IMPORTANT: Fixture files must be placed in the src
directory when using Create React App, in order for Cosmos to bundle in the exact same environment as Create React App's.
Wrapping components inside fixtures is easy, but can become repetitive. Decorators can be used to apply one or more component wrappers to a group of fixtures automatically.
A cosmos.decorator
file looks like this:
// cosmos.decorator.js
export default ({ children }) => <Provider store={store}>{children}</Provider>;
A decorator only applies to fixture files contained in the decorator's directory. Decorators can be composed, in the order of their position in the file system hierarchy (from outer to inner).
Migrating Cosmos Classic proxies to React Cosmos 5 is not intuitive. Sorry for that! Check out the nested decorators example and join the #proxies-upgrade
Slack channel to learn more about this and to get help with your migration.
Check out react-cosmos-redux to see what an advanced React Cosmos decorator looks like.
Coming up with dummy prop values is all that's required to create fixtures for many components. In other cases, however, components have special needs.
Some components need to be wrapped in certain contexts, like a Router provider. Other components fire fetch
requests willy-nilly. All these implicit dependencies are component inputs and understanding them goes a long way.
The react-mock project provides ways for mocking implicit component dependencies and helps you create fixtures for stubborn components.
The props panel allows you to manipulate component props visually by default. But you can also get a custom control panel by manually defining the UI controls in your fixtures.
// CounterButton.fixture.jsx
import { useValue } from 'react-cosmos/fixture';
export default () => {
const [count, setCount] = useValue('count', { defaultValue: 0 });
return <CounterButton count={count} increment={() => setCount(count + 1)} />;
};
// Button.fixture.jsx
import { useSelect } from 'react-cosmos/fixture';
export default () => {
// useSelect also returns a setter as the second value in the return tuple,
// like the useState hook, in case you want to change the value programatically.
const [buttonType] = useSelect('buttonType', {
options: ['primary', 'secondary', 'danger'],
});
return <Button type={buttonType}>Press me</Button>;
};
Heads up:
useValue
anduseSelect
(and Cosmos in general) work great with TypeScript.
A main feature of the React Cosmos redesign is the brand-new UI plugin architecture. While the new UI is created 100% from plugins, the plugin API is not yet documented nor made accessible. It will take a few big steps to get there, but this is the future.
Custom responsive viewports
responsivePreview
is a plugin included by default, and you can customize it through the Cosmos config.
{
"ui": {
"responsivePreview": {
"devices": [
{ "label": "iPhone 5", "width": 320, "height": 568 },
{ "label": "iPhone 6", "width": 375, "height": 667 },
{ "label": "iPhone 6 Plus", "width": 414, "height": 736 },
{ "label": "Medium", "width": 1024, "height": 768 },
{ "label": "Large", "width": 1440, "height": 900 },
{ "label": "1080p", "width": 1920, "height": 1080 }
]
}
}
}
Run cosmos-export
and get a nice component library that you can deploy to any static hosting service. The exported version won't have all the Cosmos features available in development (like opening the selected fixture in your code editor), but allows anybody with access to the static export URL to browse fixtures and play with component inputs.
Use http-server or any static file server to load the export locally.
npm run cosmos-native
React Cosmos works great with React Native. Put the following inside App.js
to get started.
import React, { Component } from 'react';
import { NativeFixtureLoader } from 'react-cosmos/native';
// You generate cosmos.userdeps.js when you start the Cosmos server
import { rendererConfig, fixtures, decorators } from './cosmos.userdeps.js';
export default class App extends Component {
render() {
return (
<NativeFixtureLoader
rendererConfig={rendererConfig}
fixtures={fixtures}
decorators={decorators}
/>
);
}
}
Once your fixtures are loading properly, you'll probably want to split your App entry point to load Cosmos in development and your root component in production. Something like this:
module.exports = global.__DEV__
? require('./App.cosmos')
: require('./App.main');
IMPORTANT: React Native blacklists __fixtures__
dirs by default. Unless you configure Cosmos to use a different directory pattern, you need to override getBlacklistRE
in the React Native CLI config.
Run cosmos --external-userdeps
instead of cosmos-native
and Cosmos will mirror your fixtures on both DOM and Native renderers.
Do NOT use these APIs in your fixture files, or any of your client code, as they require access to the file system and may bundle unwanted Node code in your client build.
Fetching a Cosmos config can be done in a number of ways, depending on whether or not you have a config file and, in case you do, if you prefer to specify the path manually or to rely on automatic detection.
detectCosmosConfig
uses the same config detection strategy as the cosmos
command.
import { detectCosmosConfig } from 'react-cosmos';
const cosmosConfig = detectCosmosConfig();
getCosmosConfigAtPath
is best when you don't want to care where you run a script from.
import { getCosmosConfigAtPath } from 'react-cosmos';
const cosmosConfig = getCosmosConfigAtPath(require.resolve('./cosmos.config'));
The minimum requirement to create a config is a root directory.
import { createCosmosConfig } from 'react-cosmos';
const cosmosConfig = createCosmosConfig(__dirname);
You can also customize your config programatically, without the need for an external config file.
import { createCosmosConfig } from 'react-cosmos';
const cosmosConfig = createCosmosConfig(__dirname, {
// Options... (TypeScript is your friend)
});
Get all your fixtures programatically. A ton of information is provided for each fixture, enabling you to hack away on top of React Cosmos. To generate visual snapshots from your fixtures, you load rendererUrl
in a headless browser like Puppeteer and take a screenshot on page load. You can compare visual snapshots between deploys to catch sneaky UI regressions.
import { getFixtures2 } from 'react-cosmos';
const fixtures = getFixtures2(cosmosConfig);
console.log(fixtures);
// [
// {
// "absoluteFilePath": "/path/to/components/pages/Error/__fixtures__/not-found.js",
// "fileName": "not-found",
// "name": null,
// "parents": ["pages", "Error"]
// "playgroundUrl": "http://localhost:5000/?fixtureId=%7B%22path%22%3A%22components%2Fpages%2FError%2F__fixtures__%2Fnot-found.js%22%2C%22name%22%3Anull%7D",
// "relativeFilePath": "components/pages/Error/__fixtures__/not-found.js",
// "rendererUrl": "http://localhost:5000/static/_renderer.html?_fixtureId=%7B%22path%22%3A%22components%2Fpages%2FError%2F__fixtures__%2Fnot-found.js%22%2C%22name%22%3Anull%7D",
// "treePath": ["pages", "Error", "not-found"]
// },
// ...
See a more complete output example here.
Aside from the fixture information showcased above, each fixture object returned also contains a getElement
function property, which takes no arguments. getElement
allows you to render fixtures in your own time, in environments like jsdom. Just as in the React Cosmos UI, the fixture element will include any decorators you've defined for your fixtures. getElement
can be used for Jest snapshot testing.
The function is called
getFixtures2
because it supersedes a previous function that's no longer documented, but wasn't removed for backwards compatibility.
- Set
webpack.configPath
toreact-scripts/config/webpack.config
. Unless you use react-app-rewired (see below). - Make sure to place fixture and decorator files in the
src
directory. - Set
staticPath
topublic
to load static assets inside React Cosmos. - Restrict
watchDirs
tosrc
to ignore file changes outside the source directory.
This is a cosmos.config.json
example for Create React App:
{
"staticPath": "public",
"watchDirs": ["src"],
"webpack": {
"configPath": "react-scripts/config/webpack.config"
}
}
In a standard Create React App setup you config React Cosmos to use CRA's internal webpack config (see above). With react-app-rewired, however, create the following webpack config in your project root instead.
// webpack.config.js
const { paths } = require('react-app-rewired');
const overrides = require('react-app-rewired/config-overrides');
const config = require(paths.scriptVersion + '/config/webpack.config.dev');
module.exports = overrides.webpack(config, process.env.NODE_ENV);
React Cosmos picks up
webpack.config.js
automatically. Usewebpack.configPath
if you prefer to customize the webpack config path.
CRACO is an alternative to react-app-rewired for overriding CRA's internal webpack config. Tailwind CSS recommends using CRACO to override CRA's PostCSS settings, which is why this guide targets CRACO and Tailwind CSS together.
- Create
webpack.config.js
in your root folder (if you haven't already) with the following contents:
/* webpack.config.js */
const { createWebpackDevConfig } = require('@craco/craco');
const cracoConfig = require('./craco.config.js');
const webpackConfig = createWebpackDevConfig(cracoConfig);
module.exports = webpackConfig;
- If you're using Tailwind CSS or another similar CSS library, add your global CSS to
globalImports
in the Cosmos config. Createcosmos.config.json
in your root folder (if you haven't already) with the following contents:
{
"globalImports": ["src/index.css"],
"staticPath": "public"
}
Cosmos picks up
webpack.config.js
automatically. Since you're relying on the exported wepack config generated by CRACO, don't forgot to remove"webpack.configPath": "react-scripts/config/webpack.config"
from yourcosmos.config.json
if you previously set it. Usewebpack.configPath
if you prefer to customize the webpack config path.
globalImports
accepts an array of paths and you can add additional global CSS files like this:"globalImports": ["src/index.css", "src/app.css"]
.
Currently Cosmos doesn't work with Next.js v10.0.6 or above. Downgrade to
next@10.0.5
until the issue is resolved. Read #1289 for more context.
The following steps are required for running Cosmos in Next.js v10. This repo is a working example. Ask for help if you're having issues integrating Cosmos with an older version of Next.js.
- Install
html-webpack-plugin@4
as a dev dependency. - Configure Babel to use the
next/babel
preset. - Optional: Set
staticPath
topublic
to load static assets inside Cosmos. - Optional: Add
styles/globals.css
toglobalImports
to automatically load global CSS in Cosmos fixtures.
This is a cosmos.config.json
example for Next.js:
{
"globalImports": ["styles/globals.css"],
"staticPath": "public"
}
This is a .babelrc
example for Next.js:
{
"presets": ["next/babel"],
"plugins": []
}
Warning: Most React Cosmos issues are related to missing build dependencies. Please see Compilation.
- Check for build errors in your terminal.
- Make sure you have html-webpack-plugin@4 installed, as well as any other build dependency.
- Try renaming
filename
in HtmlWebpackPlugin options toindex.html
, or alternatively remove HtmlWebpackPlugin from your webpack config since Cosmos will create one for you if none is found. For more details see this issue.
- Run
cosmos
with the--external-userdeps
flag. This should generatecosmos.userdeps.js
. Check that file to see if your fixtures are being picked up by Cosmos. - Check your directory structure. If you are using a Cosmos config file, Cosmos will use the directory of the config file as the root of your project. If your Cosmos config file is nested in a directory that isn't an ancestor of your fixture files, Cosmos will not find your fixtures. To solve this add a
rootDir
entry to your Cosmos config pointing to your root directory.
Cosmos Classic packages have been moved to a dedicated repo, which means we can continue to maintain Cosmos Classic or even run it alongside React Cosmos 5 in the same project (during the migration period).
That said, it's ideal for all Cosmos users to use the latest version. Please let me know if you need help upgrading.
Join us on Slack for feedback and questions.