Iterating a React Design with Styled Components
Ideally, the project has unlimited resources and time. The team will start coding using a well-thought-out and highly optimized UX design. Developers will agree on the best styling approach. There will be one or more CSS experts on the team who can ensure that features and styles can be rolled out at the same time without becoming a mess.
I do see this in a large enterprise environment. This is a wonderful thing. This article does not apply to these people.
On the other hand, small startups have zero funds, only one or two front-end developers, and it takes a very short time to showcase certain features. It doesn't have to look perfect, but it should at least be reasonably presented on desktops, tablets, and mobile devices. This allows them to present it to consultants and early users; perhaps even potential investors who express interest in the concept. Once they get some cash flow from sales and/or investments, they can get a dedicated UX designer and improve the interface.
The following applies to the latter group of people.
Project launch meeting
Let's invent a company to start a project.
Solar Excursions is a small travel agency designed to serve the booming space tourism industry in the near future.
Our small development team has agreed to use React for the UI. One of our front-end developers loves Sass very much, while the other is obsessed with CSS in JavaScript. But they have a hard time completing their initial sprint goals; of course there is no time to argue about the best style approach. Both coders agree that in the long run, the choice doesn't matter as long as it is executed consistently. They are convinced that implementing style from scratch now under pressure will result in technical debt that will have to be cleaned up later.
After some discussion, the team chose to plan one or more "style refactoring" sprints. Now, we will focus on using React-Bootstrap to display some content on the screen. This way, we can quickly build effective desktop and mobile layouts without much effort.
The less time you spend on the front-end style, the better, because we also need to connect the UI to the services our back-end developers are going to launch. And, as our application architecture begins to take shape, both front-end developers agree that it is important to unit test it. They have a lot to do.
Based on my discussions with those in power, as a dedicated project manager, I worked hard on Balsamiq for at least ten minutes, providing the team with a model for booking pages on desktop and mobile devices. I think they will meet the tablet's requirements in the middle and it looks reasonable.
Sprint Zero: Review Meeting
Pizza everywhere! The team worked very hard to achieve its goals and we now have a booking page with a layout similar to the model. The architecture of the service is taking shape, but there is still a long way to go before we can connect it to the UI. During this time, front-end developers are using hard-coded simulated data structures.
Here is our UI code so far:
This is all simple React. We are using some popular Hooks technologies, but for most of you, this may be outdated.
A key point to note is that four of our five application components imported and used components from react-bootstrap. Only the main App components are not affected. This is because it just uses our custom components to combine top-level views.
<code>// App.js imports import React, { useState } from "react"; import Navigation from "./Navigation"; import Page from "./Page"; // Navigation.js imports import React from "react"; import { Navbar, Dropdown, Nav } from "react-bootstrap"; // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { Container, Row, Col } from "react-bootstrap"; // PosterCarousel.js imports import React from "react"; import { Alert, Carousel, Image } from "react-bootstrap"; // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import { Button, Card, Col, Container, Dropdown, Jumbotron, ListGroup, Row, ToggleButtonGroup, ToggleButton } from "react-bootstrap";</code>
The decision to act quickly with Bootstrap allows us to achieve our sprint goals, but we are already accumulating technical debt. These are just four affected components, but as the application grows, it's clear that the "style refactoring" sprint we planned will become increasingly difficult. We didn't even have much customization to these components. Once we have dozens of components, all of which use Bootstrap and use a lot of inline styles to beautify them, refactoring them to remove react-bootstrap dependencies would be a very terrible claim.
Rather than building more booking pipeline pages, the team decided we would spend the next sprint to isolate react-bootstrap usage in the custom component toolkit, as our service is still under construction. Application components will only use the components in this toolkit. This way, the process becomes much easier when we separate from react-bootstrap. We don't have to refactor the usage of thirty react-bootstrap Buttons throughout the application, we just need to rewrite the inside of the KitButton component.
First sprint: Review meeting
OK, it's easy. High high. The visual appearance of the UI has not changed, but we now have a "kit" folder, which is a sibling folder of "components" in our React source code. It has a lot of files, such as KitButton.js, which basically exports the renamed react-bootstrap component.
An example component in our toolkit looks like this:
<code>// KitButton.js import { Button, ToggleButton, ToggleButtonGroup } from "react-bootstrap"; export const KitButton = Button; export const KitToggleButton = ToggleButton; export const KitToggleButtonGroup = ToggleButtonGroup;</code>
We package all toolkit components into a module like this:
<code>// kit/index.js import { KitCard } from "./KitCard"; import { KitHero } from "./KitHero"; import { KitList } from "./KitList"; import { KitImage } from "./KitImage"; import { KitCarousel } from "./KitCarousel"; import { KitDropdown } from "./KitDropdown"; import { KitAttribution } from "./KitAttribution"; import { KitNavbar, KitNav } from "./KitNavbar"; import { KitContainer, KitRow, KitCol } from "./KitContainer"; import { KitButton, KitToggleButton, KitToggleButtonGroup } from "./KitButton"; export { KitCard, KitHero, KitList, KitImage, KitCarousel, KitDropdown, KitAttribution, KitButton, KitToggleButton, KitToggleButtonGroup, KitContainer, KitRow, KitCol, KitNavbar, KitNav };</code>
Now our application components do not have react-bootstrap at all. Here is the import of the affected components:
<code>// Navigation.js imports import React from "react"; import { KitNavbar, KitNav, KitDropdown } from "../kit"; // Page.js imports import React from "react"; import PosterCarousel from "./PosterCarousel"; import DestinationLayout from "./DestinationLayout"; import { KitContainer, KitRow, KitCol } from "../kit"; // PosterCarousel.js imports import React from "react"; import { KitAttribution, KitImage, KitCarousel } from "../kit"; // DestinationLayout.js imports import React, { useState, useEffect } from "react"; import { KitCard, KitHero, KitList, KitButton, KitToggleButton, KitToggleButtonGroup, KitDropdown, KitContainer, KitRow, KitCol } from "../kit";</code>
Here is our current front-end code base:
Although we include all react imports in our toolkit component, our application components still rely on react-bootstrap implementations because the properties we place on the toolkit component instance are the same as those of react-bootstrap. This limits us when reimplementing the toolkit component because we need to adhere to the same API. For example:
<code>// 来自Navigation.js<kitnavbar bg="dark" fixed="top" variant="dark"></kitnavbar></code>
Ideally, when we instantiate the KitNavbar, we don't have to add those react-bootstrap-specific properties.
Front-end developers promise to refactor these properties as they continue, because we have identified them as problematic. Any new reference to the react-bootstrap component will go to our toolkit instead of going directly to the application component.
At the same time, we share our simulation data with server engineers, who are working hard to build a separate server environment, implement database patterns, and expose some services to us.
This gives us time to add some shine to our UI on the next sprint – which is great because those in power want to see separate themes for each destination. When the user browses the destination, we need to change the UI color scheme to match the displayed travel poster. Additionally, we hope to try to improve these components to start developing our own look and feel. Once we have some income, we will ask the designer to do a full overhaul, but hopefully we can find a suitable solution for early users.
Second Sprint: Review Meeting
Wow! The team really did their best in this sprint. We obtained themes for each destination, custom components, and removed many residual react-bootstrap API implementations from the application components.
Here is the current desktop appearance:
To achieve this, front-end developers introduced the Styled Components library. It makes it a breeze to style individual toolkit components and add support for multiple themes.
Let's take a look at some of the highlights of their sprint.
First, for global content like importing fonts and setting page body styles, we have a new toolkit component called KitGlobal.
<code>// KitGlobal.js import { createGlobalStyle } from "styled-components"; export const KitGlobal = createGlobalStyle` body { @import url('https://fonts.googleapis.com/css?family=Orbitron:500|Nunito:600|Alegreya Sans SC:700'); background-color: ${props => props.theme.foreground}; overflow-x: hidden; } `;</code>
It uses the createGlobalStyle helper function to define the CSS of the body element. It imports the web fonts we need from Google, sets the background color to the Foreground value of the current theme, and turns off overflow in the x direction to eliminate nasty horizontal scrollbars. We use the KitGlobal component in the render method of the App component.
Also in the App component, we import ThemeProvider from styled-components from ../theme and content named "themes". We use React's useState to set the initial theme to themes.luna and use React's useEffect to call setTheme when the "destination" changes. The returned component is now wrapped in ThemeProvider, which passes "theme" as a prop. The following are the complete App components.
<code>// App.js import React, { useState, useEffect } from "react"; import { ThemeProvider } from "styled-components"; import themes from "../theme/"; import { KitGlobal } from "../kit"; import Navigation from "./Navigation"; import Page from "./Page"; export default function App(props) { const [destinationIndex, setDestinationIndex] = useState(0); const [theme, setTheme] = useState(themes.luna); const destination = props.destinations[destinationIndex]; useEffect(() => { setTheme(themes[destination.theme]); }, [destination]); return (<themeprovider theme="{theme}"><react.fragment><kitglobal></kitglobal><navigation destinationindex="{destinationIndex}" setdestinationindex="{setDestinationIndex}"></navigation><page destinationindex="{destinationIndex}" setdestinationindex="{setDestinationIndex}"></page></react.fragment></themeprovider> ); }</code>
KitGlobal renders like any other component. There is nothing special there, just the body tag is affected. ThemeProvider uses the React Context API to pass the theme to any component that needs it (all components). To fully understand this, we also need to see what the subject is.
To create a theme, one of our front-end developers took all the travel posters and created a palette for each poster by extracting the highlighted colors. This is quite simple.
Obviously, we won't use all colors. This method mainly refers to the two most commonly used colors as foreground and background. Then we took three more colors, usually arranged from the lightest to the deepest, as accent1, accent2 and accent3. Finally, we chose two contrasting colors to name text1 and text2. For the above destinations, this looks like:
<code>// theme/index.js (部分列表) const themes = { ... mars: { background: "#a53237", foreground: "#f66f40", accent1: "#f8986d", accent2: "#9c4952", accent3: "#f66f40", text1: "#f5e5e1", text2: "#354f55" }, ... }; export default themes;</code>
Once we create a theme for each destination and it is passed to all components (including the toolkit components from which our application components are now built), we need to use styled-components to apply these theme colors as well as our custom visual styles such as panel corners and "Border Glow".
Here is a simple example where we have the KitHero component apply themes and custom styles to Bootstrap Jumbotron:
<code>// KitHero.js import styled from "styled-components"; import { Jumbotron } from "react-bootstrap"; export const KitHero = styled(Jumbotron)` background-color: ${props => props.theme.accent1}; color: ${props => props.theme.text2}; border-radius: 7px 25px; border-color: ${props => props.theme.accent3}; border-style: solid; border-width: 1px; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; font-family: "Nunito", sans-serif; margin-bottom: 20px; `;</code>
In this case, we can use what styled-components returns, so we just have to name it KitHero and export it.
When we use it in our application it looks like this:
<code>// DestinationLayout.js (部分代码) const renderHero = () => { return (<kithero></kithero></code><h2 id="destination-header"> {destination.header}</h2> <p>{destination.blurb}</p> <kitbutton>Book Your Trip Now!</kitbutton> ); };
Then there are more complex situations where we want to preset some properties on the react-bootstrap component. For example, we have determined earlier that the KitNavbar component has a bunch of react-bootstrap properties that we would rather not pass from the application's component declaration.
Now let's see how it is handled:
<code>// KitNavbar.js (部分代码) import React, { Component } from "react"; import styled from "styled-components"; import { Navbar } from "react-bootstrap"; const StyledBootstrapNavbar = styled(Navbar)` background-color: ${props => props.theme.background}; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; display: flex; flex-direction: horizontal; justify-content: space-between; font-family: "Nunito", sans-serif; `; export class KitNavbar extends Component { render() { const { ...props } = this.props; return ; } }</code>
First, we use styled-components to create a component named StyledBootstrapNavbar. We can use the CSS passed to styled-components to handle some properties. However, in order to continue taking advantage of the (current) components’ reliable stickiness to the top of the screen (while everything else is scrolled), our front-end developers chose to continue using react-bootstrap’s fixed property. To do this, we must create a KitNavbar component that renders an instance of StyledBootstrapNavbar using the fixed=top property. We also pass all props, including its child elements.
If we want to explicitly set certain properties in the toolkit component by default, we just need to create a separate class to render the work of styled-component and pass props to it. In most cases, we just have to name and return the output of styled-component and use it like what KitHero did above.
Now when we render the KitNavbar in the Navigation component of the application, it looks like this:
<code>// Navigation.js (部分代码) return (<kitnavbar><kitnavbarbrand><kitlogo></kitlogo> Solar Excursions</kitnavbarbrand> {renderDestinationMenu()}</kitnavbar> );</code>
Finally, we first tried to refactor the toolkit component from react-bootstrap. The KitAttribution component is a Bootstrap Alert, which for our purposes is nothing more than a normal div. We were able to easily refactor it to remove its dependency on react-bootstrap.
Here is the component that appears from the previous sprint:
<code>// KitAttribution.js (使用react-bootstrap) import { Alert } from "react-bootstrap"; export const KitAttribution = Alert;</code>
This is what it is now:
<code>// KitAttribution.js import styled from "styled-components"; export const KitAttribution = styled.div` text-align: center; background-color: ${props => props.theme.accent1}; color: ${props => props.theme.text2}; border-radius: 7px 25px; border-color: ${props => props.theme.accent3}; border-style: solid; border-width: 1px; box-shadow: 0 0 1px 2px #fdb813, 0 0 3px 4px #f8986d; font-family: "Alegreya Sans SC", sans-serif; > a { color: ${props => props.theme.text2}; font-family: "Nunito", sans-serif; } > a:hover { color: ${props => props.theme.background}; text-decoration-color: ${props => props.theme.accent3}; } `;</code>
Note that we no longer import react-bootstrap, but use styled.div as component base. They won't all be that easy, but it's a process.
Here are the results of the style and theme design work our team did during this sprint:
Check out the theme page itself here.
in conclusion
After three sprints, our team is successfully building the scalable component architecture of the UI.
- We are moving forward quickly due to react-bootstrap, but no longer amasses of large amounts of technical debt.
- Thanks to styled-components, we are able to implement multiple themes (just like almost every application on the internet today has dark and light patterns). We are no longer like a ready-made Bootstrap application.
- By implementing a custom component toolkit that contains all references to react-bootstrap, we can refactor it as needed.
Fork the final code base on GitHub.
The above is the detailed content of Iterating a React Design with Styled Components. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics





It's out! Congrats to the Vue team for getting it done, I know it was a massive effort and a long time coming. All new docs, as well.

With the recent climb of Bitcoin’s price over 20k $USD, and to it recently breaking 30k, I thought it’s worth taking a deep dive back into creating Ethereum

I had someone write in with this very legit question. Lea just blogged about how you can get valid CSS properties themselves from the browser. That's like this.

I'd say "website" fits better than "mobile app" but I like this framing from Max Lynch:

The other day, I spotted this particularly lovely bit from Corey Ginnivan’s website where a collection of cards stack on top of one another as you scroll.

If we need to show documentation to the user directly in the WordPress editor, what is the best way to do it?

There are a number of these desktop apps where the goal is showing your site at different dimensions all at the same time. So you can, for example, be writing

Questions about purple slash areas in Flex layouts When using Flex layouts, you may encounter some confusing phenomena, such as in the developer tools (d...
