DEV Community

Cover image for Adaptive React.js Duotone component
Jim Raptis
Jim Raptis

Posted on • Edited on • Originally published at jimraptis.com

4

Adaptive React.js Duotone component

This tutorial is about creating a simple duotone React.js component you can easily tweak.

Duotone design refers to creations that are made up of two contrasting colors. Much like what it describes, the word “duotone” has two parts: “duo,” meaning double, and “tone,” meaning color.

If you're impatient like me, grab the Codesandbox code right away.

Let's start!

Setup

The best way to start building a new single-page application in React in by using create-react-app. Replace the duotone-app text with your app's name.

  npx create-react-app duotone-app
Enter fullscreen mode Exit fullscreen mode

The only external library is the CSS-in-JS library React styled-components. It comes in handy when you want to pass variables in your CSS. The installation command is the following:

  yarn add styled-components
Enter fullscreen mode Exit fullscreen mode

How it works

Our approach is based on the hacky way described in this tweet by Una Kravetz.

Duotone images are so #trendy right now 😎

Had some airport time so I drew out how to get this effect w/one div in CSS 😊 #devdoodles pic.twitter.com/WENOWlwcUY

— Una Kravets 👩🏻‍💻 (@una) October 25, 2017

The image is set as a background-image of a div element. Then, we utilize the ::before and ::after selectors to add two colored overlay layers above the div. The hack is on using the CSS property mix-blend-mode to blend the overlay layers with the original image.

The mix-blend-mode CSS property sets how an element's content should blend with the content of the element's parent and the element's background.

One important point here is that the colors have to be contrasting to make the effect aesthetically pleasing!

Build the Duotone component

The React component will get as props the url of your image and two contrasting colors:

<Duotone
  src="https://source.unsplash.com/random"
  lightColor={lightColor}
  darkColor={darkColor}
/>
Enter fullscreen mode Exit fullscreen mode

Defining the actual div element with the background-image property is our 1st task.

const Duotone = styled.div`
  background-image: url(${props => props.src});
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: 50% 50%;

  position: relative;

  /* Setup the fixed dimensions */
  width: 225px;
  min-height: 400px;
`
Enter fullscreen mode Exit fullscreen mode

The position: relative rule is necessary to position the overlay layers relative to the original div. Unfortunately, there is one small drawback with this method. You have to specifically know and set the dimension of your image.

Now, we're ready to apply the selectors that represent the overlay layers. The ::before selector sets as background color the lightColor with mix-blend-mode: darken. In that way, the background is replaced with the content where the content is , otherwise, it is left as it was.

&::before {
  background-color: ${props => props.lightColor};
  content: "";
  display: block;
  border-radius: 32px;
  width: 100%;
  height: 100%;
  mix-blend-mode: darken;
  position: absolute;
}
Enter fullscreen mode Exit fullscreen mode

Then, we simple apply the ::after selector too. Here, the backgroud get the darkColor and set the CSS rule mix-blend-mode: lighten to replace the background with the content where the content is lighter.

&::after {
  background-color: ${props => props.darkColor};
  content: "";
  display: block;
  border-radius: 32px;
  width: 100%;
  height: 100%;
  mix-blend-mode: lighten;
  position: absolute;
}
Enter fullscreen mode Exit fullscreen mode

Our component is ready!

Real-life use case

I used the Duotone component for the root page of my blog.

As you've already noticed, the blog has multiple theming options. The problem was how could I adapt my header image to the active theme. My initial thought was to use a gradient overlay above the image. But I didn't like this idea due to its aesthetic result.

By implementing the Duotone component, I was able to easily customize the image based on the active primary and secondary colors and produce an eye-catching effect.

Theming v2

- More color palettes
- Adaptive duotone effect based on the active theme pic.twitter.com/NKCAQIfTKg

— Jim Raptis💥 (@d__raptis) July 5, 2020

The final Duotone React component

Here is the final Duotone React component:

const Duotone = styled.div`
  background-image: url(${props => props.src});
  background-repeat: no-repeat;
  background-size: 100% 100%;
  background-position: 50% 50%;

  position: relative;

  /* Setup the fixed dimensions */
  width: 225px;
  min-height: 400px;


  &::before {
    background-color: ${props => props.lightColor};
    content: "";
    display: block;
    border-radius: 32px;
    width: 100%;
    height: 100%;
    mix-blend-mode: darken;
    position: absolute;
  }

  &::after {
    background-color: ${props => props.darkColor};
    content: "";
    display: block;
    border-radius: 32px;
    width: 100%;
    height: 100%;
    mix-blend-mode: lighten;
    position: absolute;
  }
`
Enter fullscreen mode Exit fullscreen mode

If you liked this post, you can follow me on Twitter where I share daily tips about coding, design and bootstrapping micro-startups.

Imagine monitoring actually built for developers

Billboard image

Join Vercel, CrowdStrike, and thousands of other teams that trust Checkly to streamline monitor creation and configuration with Monitoring as Code.

Start Monitoring

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay