Business card design with Next.js and Emotion CSS

Eugene Musebe

Introduction

In this article, we use emotion css to design card templates in Nextjs that can be used as business cards. We demonstrate the manipulation of coloring css grids to come up with a beautiful structure flexible to any developer to use for a business venture e.g as a business card template. Based on preference, the colors can be changed and the information grid layout merged in any possible manner. Let's begin!

Codesandbox

The completed project is available on Codesandbox.

You can find the full codebase on my Github

Prerequisites

Entry-level knowledge in javascript and React/Nextjs and css.

Setting Up the Sample Project

Use npx create-next-app card-design to create a Next.js project and head to the directory using `cd card design

We begin with the backend setup. The backend involves integrating Cloudinary for media upload. We'll use our backend code to upload generated card templates.

Use this link to access the cloudinary login page. If you don't have an account you can create one and log into it to access your dashboard. The dashboard should contain environment variables necessary for cloudinary integration. To use these variables, go to your project root folder and create a new file names .env. Paste the following code and fill the blanks with your environment variables from the cloudinary dashboard.

1".env"
2CLOUDINARY_CLOUD_NAME =
3
4CLOUDINARY_API_KEY =
5
6CLOUDINARY_API_SECRET=

Use the npm run dev command to start your project.

Head to the pages/api directory and create a file named upload.js. Start by pasting the following inside

1"pages/upload"
2
3var cloudinary = require("cloudinary").v2;
4
5cloudinary.config({
6 cloud_name: process.env.CLOUDINARY_NAME,
7 api_key: process.env.CLOUDINARY_API_KEY,
8 api_secret: process.env.CLOUDINARY_API_SECRET,
9});

The above code configures our cloudinary environment keys and libraries. We can finally introduce a handler function to execute our POST request.

1"pages/upload"
2
3export default async function handler(req, res) {
4 if (req.method === "POST") {
5 let url = ""
6 try {
7 let fileStr = req.body.data;
8 const uploadedResponse = await cloudinary.uploader.upload_large(
9 fileStr,
10 {
11 resource_type: "video",
12 chunk_size: 6000000,
13 }
14 );
15 url = uploadedResponse.url
16 } catch (error) {
17 res.status(500).json({ error: "Something wrong" });
18 }
19
20 res.status(200).json({data: url});
21 }
22}

Our handler function will receive media data from the frontend, upload it and return the file's cloudinary link as a response.

Our backend is complete. Let's now design our card.

We will design our cards using emotion css. Therefore we begin by installing the necessary modules.

1npm install @emotion/react @emotion.styled

We wil be creating the necessary components and importing them where necessary.

Using css, we will create a card component and use grids to divide the component. We can then fill specific grids with colors respective to how colorful our card should look. Our project will of course include several extra components like Title and Forms. The article will however focus on creating the card component.

In the pages/index directory, replace the contents with the following

1"pages/index"
2
3export default function Home(){
4 function(
5 <>
6 <Card1 />
7 </>
8 )
9}

To create the card component in the return function we will use forwardref which is used to automatically pass a ref through a component to one of its children. start by importing forwarded and create and declaring our ref variable. Inside the Home function, create your card component and reference it in the DOM element as shown

1"pages/index"
2
3import { forwardRef, createRef} from 'react';
4export default function Home(){
5 const Card1 = forwardRef((props, ref) => (
6 <Card_1 ref={refOne} >
7
8 </Card_1>
9 ));
10 function(
11 <>
12 <Card1 ref={refOne} />
13 </>
14 )
15}

In your styles directory, create a directory named emotion/card1.js, and inside we start by creating a card component. Ensure to import the emotion module before creating your component.

1"styles/emotion/card1"
2
3import styled from "@emotion/styled";
4
5export const Card_1 = styled.div`
6 height: 220px;
7 width: 390px;
8 display: grid;
9 grid-template-columns: 2% 96% 2%;
10 grid-template-rows: 4% 92% 4%;
11 position: relative;
12 margin-left: 15%;
13 overflow: hidden;
14 box-shadow: 2px 5px 15px 0px #17161694;
15 background-color: #122529;
16 &:hover {
17 transform: scale(1.1);
18 transition: 0.3s;
19 }
20`;

The above code creates a card component. I put a background color for it to be visible enough. Everything else shall be done inside the card container. Ensure to import it in the index directory for the code to run.

Below is a preview of the above

We now introduce a color grid in which we will contain our colored designs. Add the code below to the styles/emotion/card1 directory.

1"styles/emotion/card1"
2
3export const ColorGrid = styled.div`
4 display: grid;
5 grid-template-columns: repeat(3, 150px);
6 grid-template-rows: repeat(8, 50px);
7 grid-gap: 8px;
8 width: 150px;
9 height: 400px;
10 transform: rotate(-45deg);
11`;

After importing the code above in the index directory, include the component inside the card component as shown below

1"pages/index"
2
3export default function Home(){
4 const Card1 = forwardRef((props, ref) => (
5 <Card_1 ref={refOne} >
6 <ColorGrid>
7 </ColorGrid>
8 </Card_1>
9 ));
10 function(
11 <>
12 <Card1 ref={refOne} />
13 </>
14 )
15}

You can view your color grid through your browser inspects section. Yor color grid should look like below:

With the color grid set up, we are ready to include our colors as we see fit. The trick is to select the specific grids and fill the background with respective colors. This article will use the color red and green for our card component.

Head to the emotion/card1 directory and add the following

1"styles/emotion/card1"
2
3
4export const Black = styled.div`
5 margin-left: 30%;
6 background-color: #343536;
7 grid-column: 2 / span 2;
8 grid-row: 1 / span 3;
9`;
10
11export const Red1 = styled.div`
12 background-color: #e45e4f;
13 grid-row: 2 / span 5;
14`;
15
16export const Red2 = styled.div`
17 background-color: #e45e4f;
18 grid-column: 2 / span 2;
19 grid-row: 4/7;
20`;
21
22export const Green = styled.div`
23 background-color: #007e67;
24 grid-column: 2/4;
25 grid-row: 7/9;
26`;

In the code above as earlier stated. we set the property background-color of specific grids and use the span property to stretch the space our color occupies.

For a clearer picture of what we just did import the color components inside the index directory and include them in your ColorGrid. Your final card component should look like below

1"pages/index"
2
3export default function Home(){
4 const Card1 = forwardRef((props, ref) => (
5 <Card_1 ref={refOne} >
6 <ColorGrid>
7 <Red1 />
8 <Red2 />
9 <Green />
10 </ColorGrid>
11 </Card_1>
12 ));
13 function(
14 <>
15 <Card1 ref={refOne} />
16 </>
17 )
18}

The above code completes our card template component. It should result in a display like shown

That's it. The template above is ready to be used to design any card, for the purpose of a business card in this article we include a demonstration.

There can be several ideas respective of the developer on how information in the card can be displayed. In our case, we will build an app that captures the template above and stores it online for future reference as well as demonstrates an example of displaying information in the card.

We will also create a second card template that can be used like the card above to help[ find a clearer picture of the css grid functionalities we've learned.

In our app, a user can select one of these templates which will be saved online, and explore an example of how the templates can be used through a form that feeds information to an information grid that will be appended on top of the card.

The final card will only be for demonstration purposes considering a developer/user can have their own ideas on how information in the card will be displayed.

Use the code below to design your form

1"pages/index"
2
3
4export const FormContainer = styled.div`
5 position: relative;
6 width: 350px;
7 height: 100%;
8 border-radius: 20px;
9 padding: 40px;
10 background: #ecf0f3;
11 box-shadow: 14px 14px 20px #cbced1, -14px -14px 20px white;
12`;
13export const Inputs = styled.div`
14 text-align: left;
15 margin-top: 10px;
16`;
17
18export const Label = styled.h4`
19 display: block;
20 width: 100%;
21 padding: 0;
22 border: none;
23 outline: none;
24 box-sizing: border-box;
25 margin-bottom: 4px;
26 margin-top: 12px;
27 font-family: 'Josefin Sans', sans-serif;
28`;
29
30export const Input = styled.input`
31 display: block;
32 width: 100%;
33 padding: 0;
34 border: none;
35 outline: none;
36 box-sizing: border-box;
37 background: #ecf0f3;
38 padding: 10px;
39 padding-left: 20px;
40 height: 45px;
41 font-size: 14px;
42 border-radius: 50px;
43 box-shadow: inset 6px 6px 6px #cbced1, inset -6px -6px 6px white;
44 &:placeholder {
45 color: gray;
46 }
47`;

Based on information you'd like to apper on your card you can use state hooks to feed data to your form which will allow it to appear on your card.

1"pages/index"
2
3
4<FormContainer>
5 <Inputs>
6 <Label>Name</Label>
7 <Input
8 id="name"
9 placeholder="Full Name"
10 onChange={(e) => {
11 setName(e.target.value);
12 }}
13 />
14 <Label>Company / Business Name</Label>
15 <Input
16 id="brandname"
17 placeholder="company / brand / name"
18 onChange={(e) => {
19 setBrand(e.target.value);
20 }}
21 />
22 <Label>Phone Number</Label>
23 <Input
24 id="phonenumber"
25 placeholder="070000000"
26 onChange={(e) => {
27 setPhoneNumber(e.target.value);
28 }}
29 />
30 <Label>Email</Label>
31 <Input
32 id="email"
33 placeholder="example@test.com"
34 onChange={(e) => {
35 setEmail(e.target.value);
36 }}
37 />
38 <Label >Location</Label>
39 <Input
40 id="location"
41 type="location"
42 placeholder="location"
43 onChange={(e) => {
44 setLocation(e.target.value);
45 }}
46 />
47 <Label >Website</Label>
48 <Input
49 id="website"
50 type="website"
51 placeholder="website"
52 onChange={(e) => {
53 setWebsite(e.target.value);
54 }}
55 />
56
57 </Inputs>
58 </FormContainer>

Create another card component to show your final card display demo. After a template is selected, the background will be uploaded to cloudinary and imported to the final card as a background. The information grid can then be appended to this background. Use the code below to create an information grid` sample

1"styles/emotion/card1"
2
3export const InfoGrid = styled.div`
4grid-column: 2/3;
5grid-row: 2/3;
6z-index: 2;
7width: 100%;
8height: 100%;
9background-color: rgba(255, 255, 255, 0.363);
10box-shadow: 0px 2px 15px rgba(0, 0, 0, 0.432);
11border-radius: 6px;
12font-size: 0.7rem; /*12px;*/
13display: grid;
14grid-template-columns: 15px repeat(3, 1fr) 15px;
15grid-template-rows: repeat(3, 1fr);
16line-height: 1px;
17margin-=top: 10px;
18`;
19
20export const Name = styled.h2`
21 grid-column: 1 / span 2;
22 grid-row: 1 / span 1;
23 font-size: 1.2em;
24 letter-spacing: 0.1rem;
25 margin-top: 15px;
26 font-size: 20px;
27 background: transparent;
28`;
29
30
31export const Brand = styled.p`
32 grid-column: 2 / span 2;
33 grid-row: 1 / span 1;
34 font-size: 1.2em;
35 letter-spacing: 0.1rem;
36 margin-top: 15%;
37 margin-left: -28%;
38 background: transparent;
39`;
40
41export const Address = styled.div`
42 grid-column: 1 / span 2;
43 grid-row: 4;
44 margin-left: -35%;
45 background: transparent;
46`;
47
48
49export const PhoneNumber = styled.div`
50 grid-column: 3 / span 2;
51 grid-row: 3;
52 text-align: end;
53 background: transparent;
54`;
55
56export const Email = styled.div`
57 grid-column: 3 / span 2;
58 grid-row: 4;
59 text-align: end;
60 background: transparent;
61`;
62
63export const CardText = styled.p`
64 font-size: 1.2em;
65 letter-spacing: 0.1rem;
66`;
67
68
69export const Back = styled.div`
70 height: 220px;
71 width: 390px;
72 box-shadow: 2px 5px 15px 0px #17161694;
73 margin-top: 10%;
74 display: flex;
75 flex-wrap: wrap;
76`;
77
78
79export const NameTag = styled.div`
80 margin-top: 0px;
81 width: 100%;
82 height: 40%;
83 box-shadow: 2px 5px 15px 0px #17161694;
84 margin-top: 17%;
85 background: rgba(255, 255, 255, 0.363)
86
87`;
88
89
90export const TextLg = styled.h1`
91 margin: 2px;
92 font-weight: 200px;
93 font-size: 30px;
94 font-family: 'Heebo', sans-serif;
95`;
96
97export const TextSm = styled.p`
98 margin: 2px;
99 font-weight: 100px;
100 font-size: 15px;
101 font-family: 'Heebo', sans-serif;
102`;

The codes explained above results in the grid shown below:

That's it! We have successfully designed our card template as well as demonstrated how it can be used to create a business card.

Let's try another card once more for a clearer understanding. Based on the information provided above, create a card component called Card2 inside the index directory using forwarded like the first card.

Create the contents of card2 inside the styles/emotion/card2.js` directory by pasting the codes below

1"emotion/card2.js"
2
3
4import styled from '@emotion/styled';
5
6
7export const Card_2 = styled.div`
8 box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
9 display: grid;
10 grid-template-columns: repeat(12, 1fr);
11 grid-template-rows: repeat(4, 1fr);
12 width: 390px;
13 height: 220px;
14 font-family: 'Trebuchet MS', sans-serif;
15 &:hover {
16 transform: scale(1.1);
17 transition: 0.3s;
18 }
19`;
20
21export const Purple = styled.div`
22 background-color: #871F78;
23 grid-column: 8 / span 5;
24 grid-row: 1 / span 4;
25`;
26
27export const Yellow2 = styled.div`
28 background-color: #F2B900;
29 grid-column: 1 / span 7;
30 grid-row: 1 / span 4;
31`;
32
33export const Pink2 = styled.div`
34 background-color: #fa001a;
35 -webkit-clip-path: polygon(0% 0%, 100% 0%, 0% 100%);
36 clip-path: polygon(0% 0%, 100% 0%, 0% 100%);
37 grid-row: 1 / span 3;
38 grid-column: 1 / span 11;
39 position: relative;
40 z-index: 2;
41`;
42
43export const Dots2 = styled.div`
44 background: radial-gradient(#fa001a 20%, transparent 19%),
45 radial-gradient(#fa001a 20%, transparent 19%), transparent;
46 background-size: 6px 6px;
47 background-position: 0 0, 3px 3px;
48 grid-column: 1 / span 12;
49 grid-row: 3 / span 2;
50 margin: 0 0 15px 20px;
51 z-index: 1;
52`;
53
54export const Intro = styled.div`
55 background: black;
56 color: white;
57 display: flex;
58 flex-direction: column;
59 grid-column: 4 / span 6;
60 grid-row: 2 / span 2;
61 justify-content: center;
62 text-align: center;
63 z-index: 3;
64`;
65
66export const FrontName = styled.p`
67 letter-spacing: 1px;
68 text-transform: uppercase;
69 font-size: 18px;
70`;
71
72export const FrontBrand = styled.p`
73 letter-spacing: 1px;
74 text-transform: uppercase;
75 font-size: 8px;
76 margin-top: 5px;
77`;
78
79
80export const Back2 = styled.div`
81 box-shadow: 0 14px 28px rgba(0, 0, 0, 0.25), 0 10px 10px rgba(0, 0, 0, 0.22);
82 margin-top: 6%;
83 margin-left: 6%;
84 display: grid;
85 grid-template-columns: repeat(12, 1fr);
86 grid-template-rows: repeat(12, 1fr);
87 height: 215px;
88 width: 100%;
89 &:hover {
90 transform: scale(1.1);
91 }
92`;
93
94export const BackYellow = styled.div`
95 background-color: #f1ef1c;
96 grid-column: 1 / span 9;
97 grid-row: 1 / span 3;
98`;
99
100export const BackTopDots = styled.div`
101 background: radial-gradient(#4cc9c8 20%, transparent 19%),
102 radial-gradient(#4cc9c8 20%, transparent 19%), transparent;
103 background-size: 6px 6px;
104 background-position: 0 0, 3px 3px;
105 grid-column: 8 / span 6;
106 grid-row: 2 / span 3;
107`;
108
109export const BackInfo = styled.div`
110 grid-column: 2 / span 6;
111 grid-row: 5 / span 6;
112`;
113
114export const BackName = styled.p`
115 font-size: 18px;
116 font-weight: bold;
117 letter-spacing: 1px;
118 text-transform: uppercase;
119`;
120
121export const BackBrand = styled.p`
122 font-size: 12px;
123 margin-bottom: 15px;
124`;
125
126export const BackText = styled.p`
127 font-size: 12px;
128 margin-bottom: 15px;
129`;
130
131export const BackDots = styled.div`
132 background: radial-gradient(#4cc9c8 20%, transparent 19%),
133 radial-gradient(#4cc9c8 20%, transparent 19%), transparent;
134 background-size: 6px 6px;
135 background-position: 0 0, 3px 3px;
136 grid-column: 1 / span 8;
137 grid-row: 11 / span 2;
138 z-index: 2;
139`;
140
141export const BackkPink = styled.div`
142 background-color: #fa001a;
143 grid-column: 8 / span 5;
144 grid-row: 10 / span 3;
145`;

Import all the above components in your index directory and include them in your card2 component like you did earlier with card1 using (<Card 1 ref={refTwo}/>).

1"pages/index"
2
3
4 const Card2 = forwardRef((props, ref) => (
5 <Card_2 ref={refTwo} onClick={card2Handler} >
6 <Purple />
7 <Yellow2 />
8 <Pink2 />
9 <Dots2 />
10 </Card_2>
11 ));

The result of this is like below

.

That's it! Ensure to try out the article process and enjoy the experience. Happy coding!

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.