Cosmos 4.7 — the version that shows you the future

This release has two parts:

  • For existing Cosmos users, it’s the seasonal bundle of bug fixes and improvements (15-contributor-strong!)
  • For those eager to try something new and exciting, it’s a trojan horse-esque release that contains a brand new platform at the mere flick of a switch!
Psst! What is this about, you ask? React Cosmos, a dev tool for UI developers. You may call it a “component playground” or an “isolated dev environment”, but at the end of the day all you need to remember is that it rocks. Check it out.

Meet Cosmos Next

Cosmos Next rendering a component inside a mobile viewport

Under the hood Cosmos Next has a new foundation, which essentially is my attempt at building a world class dev platform with delightful UX, while in the process relearning what good software looks like.

But enough with this nonsense!

Let’s focus on one key aspect of the public API: How fixtures are expressed. It’s paramount to get this right before moving forward. I hope you’ll read the next paragraphs and help me make the right call.

This is how an existing Cosmos fixture looks like:

component: Button,
props: {
label: 'Register',
disabled: true

A plain object with a reference to the component type and a set of props. Simple and straightforward. It does the job of expressing “Give me a Button component with these props.” This fixture is also flexible, because we can extend it with other plugin-handled attributes like state or viewport.

Over the years, however, I’ve come to realize that this isn’t the most inspired format for defining React component configurations. Why? Because, well… there’s already a way to do this!

<Button label="Register" disabled />

More concise, right?

JSX might already seem like the obvious choice to you. Or not, which is why I want to have this conversation. Let’s look at the advantages of the former approach first and then examine what JSX fixtures bring to the table.

Plain JS object fixtures are…

  1. More universal — not bound to React ecosystem
  2. Easier to handle by Cosmos (eg. to turn values into UI controls)
  3. Easier to extend with plugin-specific fields

And here’s what I think about each at the time of this writing:

  1. React Cosmos is a dev tool for React developers. While I’d like to go beyond React in the distant future, I think it’s more important for Cosmos to become highly useful in the React community before expanding. Once we get there, I’m sure we can add support for other fixture formats that fit the specific needs of other libraries.
  2. APIs should be designed for easy of use, not ease of implementation.
  3. Yes and no. Yes it’s easier to add a field to a plain object than to decorate a JSX element. The latter scales poorly because of nesting. But no, because JSX tags result in function calls that are easier to type-check. Types matter!

Now let’s examine the proposed alternative.

JSX fixtures are…

  1. More natural to React users (no need to learn a new format)
  2. Copy-pastable into source code
  3. Type-checked by default
  4. More flexible: Not bound to a single component type

I think the first three points are intuitive, so I’ll only expand on the forth.

It seemed like a good idea to bind fixtures to a component type because I‘ve been infatuated with component-driven-development since before React. But I’ve learned that binding fixtures to a single component can be impractical.

Here’s a common example:

export default (
<Button label="Click me" type="success" />
<Button label="Click me" type="warning" />
<Button label="Click me" type="error" />

Until now, Cosmos forced you to create a wrapper component to render this.

Put differently, I assumed UI fixtures should be tied to component units. In some cases, that is correct. Other times, however, we want to showcase multiple component instances together (of one or more types).

So I think JSX fixtures are more approachable and make the limitations of the previous format obsolete, at the cost of introducing JSX nesting. What do you think?

But this is a breaking change! 😱

This discussion can be uncomfortable for existing Cosmos users. Myself included. So I’m not taking this change lightly. Here’s the plan:

  • Cosmos stable isn’t going anywhere. If you don’t have time to engage at this stage, no worries. Continue using Cosmos as is and stay updated. The next steps for Cosmos Next are: Validate new APIs, reach feature parity with Cosmos stable, and only then work out the transition strategy.
  • If you want to be a part of this redesign, great. Cosmos Next is already a viable product and available to anyone who has Cosmos 4.7 installed. Follow this brief upgrade guide. Report any obstacles you encounter.

What about decorators? What’ll happen to “proxies”?

I’m glad you asked.

Even test fixtures require reusable parts. And if you know Cosmos, you’ve probably used or even authored proxies. Proxies work, but they are more complicated than they need to be (as well as poorly named). JSX fixtures simplify this, too. Read the guide and you’ll see.

There are loads of other things about Cosmos Next that I’m dying to tell you about (some hidden behind feature flags), but I want to keep this on point. Let’s decide what’s the best format for component fixtures, and move on.

OK, now what?