Generate Social Images for Blog Posts

Ifeoma Imoh

Have you shared a link to a post on any social platform and been unhappy with the image displayed because it didn't fit the article title or your brand? In this article, we will build an application that dynamically generates social images based on a template.

You can use an image or a banner that suits your brand as a base image, and with Cloudinary, we can dynamically layer texts on that image to generate custom social images for blog posts.

Here is a link to the demo on CodeSandbox.

Create a Design Layout

We need a banner that will serve as the base image. You can choose a random background if you don't have one that suits your brand or design a custom layout using any design tool (Figma, Adobe XD, Sketch, e.tc).

For this tutorial, I will be using this simple layout I designed with Figma.

Cloudinary Setup

First, we need to upload our image to Cloudinary. If you are new to Cloudinary, you can sign up here for a free account. After successful signup, see this documentation for options on uploading assets to your Cloudinary Media Library. Upload the image you want to use as your base image and assign it a name you can easily remember.

Project Setup

Open your terminal and run the following command to create a React application in a folder named social-media-card.

1npx create-react-app social-image-template

Next, let's install the dependencies we will need for this project. Run the following command to install them.

1npm install cloudinary-react --save

The command above installs the Cloudinary's React SDK.

After the installation, and add the following to the App.js file inside your src folder:

1import "./App.css";
2 import React, { useState } from "react";
3 import { Image, Transformation } from "cloudinary-react";
4
5 function PostTitle({ title, onTitleChange }) {
6 return (
7 <div>
8 <label htmlFor="blog title">Blog Title:</label>
9 <input
10 value={title}
11 onChange={onTitleChange}
12 type="text"
13 placeholder="Enter a post title"
14 />
15 </div>
16 );
17 }
18
19 function Author({ authorName, onNameChange }) {
20 return (
21 <div>
22 <label>Author:</label>
23 <input
24 value={authorName}
25 onChange={onNameChange}
26 type="text"
27 placeholder="Enter author's name"
28 />
29 </div>
30 );
31 }
32
33 const App = () => {
34 const [blogInput, setBlogInput] = useState("");
35 const [authorName, setAuthorName] = useState("");
36 return (
37 <div className="wrapper">
38 <div className="container">
39 <div className="form">
40 <form>
41 <PostTitle
42 title={blogInput}
43 onTitleChange={(e) => setBlogInput(e.target.value)}
44 />
45 <Author
46 authorName={authorName}
47 onNameChange={(e) => setAuthorName(e.target.value)}
48 />
49 <div className="button-wrapper">
50 <button>Generate Social Image</button>
51 </div>
52 </form>
53 </div>
54 </div>
55 </div>
56 );
57 };
58
59 export default App;

In the code above, we're importing two components, Image and Transformation, from the cloudinary-react library we installed.

We then defined three components. The first two components return a label and an input. They will render a UI layer for interactively modifying the post title and the author's name fields, respectively.

We also have our App component, where we defined some state variables which manage the states of our PostTitle and Author components. Our App component renders a form containing the PostTitle and Author components, and they both receive as props their states and mechanisms for updating them.

Add the following styles to your App.css file:

1.form-control {
2 display: flex;
3 align-items: center;
4 }
5 label {
6 font-weight: 700;
7 font-size: 18px;
8 width: 100px;
9 display: block;
10 }
11 input {
12 width: 70%;
13 border: 1px solid #ccc;
14 border-radius: 4px;
15 padding: 12px 20px;
16 margin: 5px 0;
17 }
18 button {
19 width: 50%;
20 background-color: #38a6d2;
21 color: white;
22 font-weight: 600;
23 font-size: 20px;
24 padding: 15px;
25 border: none;
26 border-radius: 4px;
27 cursor: pointer;
28 }
29 button:hover {
30 background-color: #37963c;
31 }
32 .button-wrapper {
33 display: flex;
34 justify-content: center;
35 margin-top: 20px;
36 }
37 .form {
38 margin: 50px;
39 background-color: #e0e6e9;
40 padding: 30px;
41 border-radius: 10px;
42 }
43 .container {
44 width: 100%;
45 }
46 .wrapper {
47 display: flex;
48 justify-content: center;
49 }

Navigate to localhost:3000 in your browser, and you should see the following:

So far, the idea is that when a user fills out the form and clicks the button, we want to generate an image based on the user's information. Let's add the logic for that.

Add the following to your App.js file:

1import "./App.css";
2 import React, { useState } from "react";
3 import { Image, Transformation } from "cloudinary-react";
4
5 function PostTitle({ title, onTitleChange }) {
6 return (
7 //...
8 );
9 }
10
11 function Author({ authorName, onNameChange }) {
12 return (
13 //...
14 );
15 }
16
17 const App = () => {
18 const [blogInput, setBlogInput] = useState("");
19 const [authorName, setAuthorName] = useState("");
20 {/* Add the following */}
21 const [showBanner, setShowBanner] = useState(false);
22 const displayImage = (e) => {
23 e.preventDefault();
24 if (blogInput && authorName) {
25 setShowBanner(true);
26 }
27 };
28
29 return (
30 //...
31 <div className="form">
32 {/* Add the onSubmit handler to the form element*/}
33 <form onSubmit={displayImage}>
34 <PostTitle
35 //...
36 />
37 <Author
38 //...
39 />
40 <div className="button-wrapper">
41 <button>Generate Social Image</button>
42 </div>
43 </form>
44 </div>
45 {/* Add the following */}
46 {showBanner && (
47 <div className="display">
48 <Image publicId={"social-card"} cloudName="ifeomaimoh">
49 <Transformation width="800" height="500" crop="fit" />
50 </Image>
51 </div>
52 )}
53 </div>
54 </div>
55 );
56 };
57 export default App;

In the App component, we added a state variable, showBanner, which stores a boolean. We can then check the value to determine whether to show the banner or not.

We then created a function called displayImage which, when called, flips the value of showBanner. The function is also passed as an event handler to the onSubmit event for the form element.

We're using the state variable showBanner to conditionally render our image with the Cloudinary Image component we imported.

To use Cloudinary React components, you need to configure your cloudName. We're specifying that directly to the Image component with the publicID of the image we uploaded to Cloudinary.

The Image component currently accepts a Transformation element that allows us to define the width and height of our image. We defined a maximum width of 500 pixels for our image template using the fit crop mode in the Transformation element.

Add Text Overlay

Next, we need to add Transformation elements to the Image component that adds and positions text overlays on our image when a user fills the form.

Add the following to the Image component in your App.js file:

1<Transformation
2 overlay={{
3 fontFamily: "Arial",
4 fontSize: 40,
5 fontWeight: "bold",
6 letter_spacing: 4,
7 text: `${blogInput}`,
8 }}
9 color="#FFFFFF"
10 width="500"
11 height="200"
12 crop="fit"
13 />
14 <Transformation flags="layer_apply" gravity="west" x="40" />
15 <Transformation
16 overlay={{
17 fontFamily: "Arial",
18 fontSize: 25,
19 text: `Author: ${authorName}`,
20 textAlign: "",
21 fontWeight: "bold",
22 }}
23 color="#FFFFFF"
24 width="100"
25 height="100"
26 crop="fit"
27 />
28 <Transformation flags="layer_apply" gravity="south_west" x="40" y="50" />

We are adding two text overlays to our image template for the post title and the author name. We're using the text property of the overlay transformation prop to dynamically add the post title and the author name to the image, depending on the information provided by the user.

For the post title, we defined a maximum width of 500px and added the fit crop mode so that if we have a multiline text, Cloudinary automatically wraps the text content to the new line.

The default text position when using the gravity parameter is center. For both overlays, we're controlling the positions of the text overlays the base image by combining the gravity parameter with the X and Y coordinates.

Now you can head over to your browser and fill in the form, then click the Generate social image button to create an image with the text overlay you entered in the form.

Here's what mine looks like:

Find the project here on GitHub.

Summary

In this post, we saw how to generate social images for blog posts using Cloudinary's cloud-based media-management solution to layer texts on an image dynamically. You can further customize this image by adding your logo or a picture of yourself.

Resources you may find useful:

Ifeoma Imoh

Software Developer

Ifeoma is a software developer and technical content creator in love with all things JavaScript.