Code with Design — How we Built a Tool to Export React Prototypes from Sketch
Every year, right before the holidays, we dedicate a week of our time at Tictail to do something that is not part of our normal work. We call this the Demo Week, and it’s a great opportunity to explore new ideas and collaborate with people you usually don’t get to work with. This can be a new experimental product feature, an improvement of a company process, a LED map of live purchases, or anything else that would improve Tictail. As the name implies however, it needs to be something that can be demoed at the end of the week.
This year, me and designer Petter Nilsson decided to explore the possibility of building a tool that connects the workflows between design and development. More specifically, we wanted to build a tool that can export our Sketch designs into fully interactive React applications. Like Airbnb’s React Sketch.app, but the other way around!
Now this might sound like a huge project to finish in just a week, but we decided on a couple of limitations of the tool to make this possible:
- The design in Sketch can only consist of pre-defined Symbols that map to our already implemented React UI components.
- The exported code will only serve as an interactive prototype to showcase the app layout and flows between different screens, similar to what Framer aims to do. The code can be used as a starting point for production implementation, but it won’t contain any real production data or business logic.
- It’s possible to export a responsive layout, but the designer will need to do the heavy lifting of figuring out the structure of rows and columns by defining those as named groups in Sketch.
Here’s what we ended up with by the end of the week:
Considering the limited time we managed to get quite far along the vision that we set out to accomplish. In this blog post I’ll try to give a high level description of how we built this tool.
Reading Sketch Files
With Sketch’s new open file format, a Sketch file is just a zipped folder with JSON files (and any bitmap images that have been used in the design). To be able to easily access this information, and to get the auto reloading seen above, I created a custom Webpack loader. The loader unzips the Sketch file in memory and returns the JSON files in a single object:
The most interesting part here is the
pages object, which contains each page in the Sketch document as a tree of layers. A layer can be a group, text component, symbol, rectangle, etc., with each layer possibly having more child layers.
The loader also uses Webpack’s
emitFile API to make any of the bitmap images available by their paths on the development server. Lastly, since most of the text data is stored as binary plists, it unpacks these fields to make them readable in the client. You can view the loader in its entirety in this Gist.
Components and Props
Now that we access to the Sketch data, we can start mapping it to React components. Luckily, since the data in Sketch is structured as a tree of layers, it translates cleanly to the tree of React components that we want to create. We can simply traverse the tree recursively, and create the corresponding React component for every layer that we encounter.
A layer in Sketch is for the most part either a Group (a folder of child layers), or a pre-defined Symbol (e.g. a button or select box). We also have special handling for Image and Text layers. The groups follow an agreed upon naming convention that we can parse to map them to container components with spacing and alignment props.
To be able to set all the props of UI components, we slightly abuse Sketch’s Symbol Overrides feature. In the example below we have a label field that’s visually represented in the Sketch document, but we also have a number of hidden fields that are only used in the mapped React component.
These fields are automatically set from the selected option in the dropdown field. The button symbol that we created in Sketch comes with a number of different types and states, so you can for example select between secondary and primary buttons, and whether the button is disabled or not.
While it would have been very easy to read the dimensions and coordinates from the Sketch document and absolutely position everything, we decided that an important feature for the tool was the ability to make the exported app responsive.
We’ve often run into situations where we have a beautiful design for the standard mobile, tablet and desktop sizes, but once you start resizing the window between these breakpoints you may find various issues that weren’t anticipated in the design. This happens because the designer doesn’t have the tools to view the design in all possible in-between sizes before it has been implemented by the developer.
To make this possible, we decided that it’s up to the designer to structure the design in terms of rows and columns that adhere to a standard 12-column grid layout. This task is something that is usually left to the developer when it’s time to implement the design, but given the right tools it makes more sense to have this step figured out already in the design process.
All the designer needs to do is to create groups named Row and Column that the elements are placed within. As with most grid layouts, a row can consist of multiple columns, and columns can themselves contain their own nested rows, continuing down recursively as far as you wish. When the code loops through this structure it can automatically detect the intended sizes for the columns, and by looking at the different screen sizes that there is an artboard for, we can map these values to their corresponding breakpoints.
The way that React allows you to express your UI in a declarative manner really opens up the possibility of building tools like these. Once you’ve implemented the UI components that are your basic building blocks of the app, it makes a lot of sense to use a visual tool to work with layout instead of a code editor. Code editors are still great when doing the heavy programming focused work, such as implementing your business logic, but I think that we as developers shouldn’t be afraid to start embracing more visual tools that can handle some of the grunt work of programming for us.
Having a more tightly integrated workflow between design and development comes with some huge benefits:
- The feedback loop for designers is vastly shortened since they don’t need to wait for the actual implementation or build prototypes using other tools to test the user experience.
- Time spent designing contributes to the production code, since a whole lot of trivial implementation time can be saved by basing the code on the work that the designer has already put into defining the layout and components.
- By having a one to one mapping between UI elements in the design and the implemented React components, the designer can gain a better understanding of where current code can be reused and where new components need to be implemented.
- Giving the tools to define how an app should behave responsively allows the designer to contribute to figuring out how components fit into the grid on different sizes, rather than leaving all of that responsibility to the developer.
While the tool that we built during this week allowed us to quickly preview our design as an interactive prototype, we never got to the actual export functionality. Building the tool was certainly a fun learning experience, but the end result didn’t end up being much more than a proof of concept.
Since the tool is heavily coupled to our own UI components, there is unfortunately not much of it that we can share with the rest of the world. But fear not — there are already a ton of interesting open-source tools that are starting to pop up within this space:
It goes far beyond checkboxes. Making a list? Draw one item, and React Studio can repeat it and fill with real data…
Alva is a radically new open source design tool built for cross-functional product teams. You can design with the same…
It will be interesting to follow the progress of these tools, and we are excited to see how we can incorporate this into our design and frontend development workflow.