71
loading...
This website collects cookies to deliver better user experience
<div>
s and <span>
s to build such UI. It gets complicated, unreadable, and hard to maintain very quickly.<div>
s (or <span>
s).import styled from "@emotion/styled";
import checkmarkImage from "path-to-file/file-name.svg";
const Circle = styled.div`
/* We're using CSS variables here. */
--primaryColor: #00ccb0;
--secondaryColor: #e1e1e1;
--scale: 2;
--size: calc(16px * var(--scale));
border-radius: 50%;
position: relative;
width: var(--size);
height: var(--size);
box-sizing: border-box;
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
margin-right: var(--size);
`;
export default Circle;
styled
from the emotion
library and an image that we will use in a moment.Circle
and add a few CSS rules that make it a nice circle.background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
background-color
based on the active
prop which will be passed by the parent component.(...)
<Circle active={true} />
<Circle active={false} />
<Circle active={false} />
(...)
::after
pseudo-element for this as shown below:const Circle = styled.div`
--primaryColor: #00ccb0;
--secondaryColor: #e1e1e1;
--scale: 2;
--size: calc(16px * var(--scale));
--linkWidth: calc(10px * var(--scale));
--linkHeight: calc(2px * var(--scale));
border-radius: 50%;
position: relative;
width: var(--size);
height: var(--size);
box-sizing: border-box;
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
margin-right: var(--size);
/* Make a pill shaped element that will act as link between two circles. */
&::after {
content: "";
width: var(--linkWidth);
height: var(--linkHeight);
border-radius: 100px;
position: absolute;
left: calc(var(--size) + ((var(--size) - var(--linkWidth)) / 2));
top: calc((var(--size) - var(--linkHeight)) / 2);
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
}
`;
First, make a rectangle with rounded borders to give it a pill-like shape using width
, height
, and border-radius
properties.
Then, align it centrally relative to the circle using top
and left
properties.
Note: We use calc
function to figure out values for top
and left
properties based on the dimension of the Circle
and Link
so that changing scale won't affect the alignment.
const Circle = styled.div`
--primaryColor: #00ccb0;
--secondaryColor: #e1e1e1;
--scale: 2;
--size: calc(16px * var(--scale));
--linkWidth: calc(10px * var(--scale));
--linkHeight: calc(2px * var(--scale));
border-radius: 50%;
position: relative;
width: var(--size);
height: var(--size);
box-sizing: border-box;
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
margin-right: var(--size);
/* Make a pill shaped element that will act as link between two circles. */
&::after {
content: "";
position: absolute;
width: var(--linkWidth);
height: var(--linkHeight);
left: calc(var(--size) + ((var(--size) - var(--linkWidth)) / 2));
top: calc((var(--size) - var(--linkHeight)) / 2);
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
border-radius: 100px;
}
/* We don't want to show the link after the last element. */
&:last-child {
&::after {
display: none;
}
}
`;
::before
pseudo-element to create it as shown below:const Circle = styled.div`
--primaryColor: #00ccb0;
--secondaryColor: #e1e1e1;
--scale: 2;
--size: calc(16px * var(--scale));
--linkWidth: calc(10px * var(--scale));
--linkHeight: calc(2px * var(--scale));
--checkmarkWidth: calc(9px * var(--scale));
--checkmarkHeight: calc(7px * var(--scale));
border-radius: 50%;
position: relative;
width: var(--size);
height: var(--size);
box-sizing: border-box;
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
margin-right: var(--size);
/* Center svg (checkmark in this case). */
&::before {
content: "";
display: ${(props) => (props.active ? "block" : "none")};
position: absolute;
top: calc((var(--size) - var(--checkmarkHeight)) / 2);
left: calc((var(--size) - var(--checkmarkWidth)) / 2);
width: var(--checkmarkWidth);
height: var(--checkmarkHeight);
background-image: url(${checkmarkImage});
}
/* Make a pill shaped element that will act as link between two circles. */
&::after {
content: "";
position: absolute;
width: var(--linkWidth);
height: var(--linkHeight);
left: calc(var(--size) + ((var(--size) - var(--linkWidth)) / 2));
top: calc((var(--size) - var(--linkHeight)) / 2);
background-color: ${(props) =>
props.active ? "var(--primaryColor)" : "var(--secondaryColor)"};
border-radius: 100px;
}
/* We don't want to show the link after the last element. */
&:last-child {
&::after {
display: none;
}
}
`;
<div>
.