{"id":38691,"date":"2025-10-02T07:00:00","date_gmt":"2025-10-02T14:00:00","guid":{"rendered":"https:\/\/cloudinary.com\/blog\/?p=38691"},"modified":"2025-10-03T09:20:15","modified_gmt":"2025-10-03T16:20:15","slug":"image-text-overlay-generator-react","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react","title":{"rendered":"How to Create an Image Text Overlay Generator With Cloudinary and React"},"content":{"rendered":"\n<p>Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered by Cloudinary. Users will upload an image straight to Cloudinary, then layer editable text, adjust its reposition, resize, tweak styling, and see instant previews driven by Cloudinary\u2019s on-the-fly transformations. We\u2019ll wire up the upload flow, model the overlay with React state, and generate URLs that encode text, size, and coordinates so the final asset is production-ready.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1759447325\/blog-How_to_Create_an_Image_Text_Overlay_Generator_With_Cloudinary_and_React-1.png\" alt=\"Man sitting on a roof with the text JUST DO IT behind him\"\/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Part 1: Set Up Your Cloudinary Credentials&nbsp;<\/h2>\n\n\n\n<p>Retrieve your Cloudinary cloud name, API key, and secret to make sure your MCP server configurations are connected to your Cloudinary application.<\/p>\n\n\n\n<p>To begin, log in to your <a href=\"https:\/\/cloudinary.com\/\">Cloudinary account or create a free account<\/a>. If prompted with the question, \u201cWhat\u2019s your main interest?\u201d, select <strong>Coding with APIs and SDKs<\/strong> or <strong>Skip<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1759447327\/blog-How_to_Create_an_Image_Text_Overlay_Generator_With_Cloudinary_and_React-2.png\" alt=\"Cloudinary login page with &quot;What's your main interest&quot; and two options: Coding with APIs and SDKs and Interactive Digital Asset Management\"\/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\">Cloudinary Cloud<\/h3>\n\n\n\n<p>In your account, select <strong>Settings <\/strong>&gt;<strong> Product Environments<\/strong>. Here, you\u2019ll see the cloud that you\u2019ve created. Let\u2019s click the three-dot menu to edit your Cloudinary cloud name.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1759447326\/blog-How_to_Create_an_Image_Text_Overlay_Generator_With_Cloudinary_and_React-3.png\" alt=\"Product Environments. Active is toggled on.\"\/><\/figure>\n\n\n\n<p>Edit the product environment and name your cloud, then click <strong>Save Changes<\/strong>.<\/p>\n\n\n\n<p>It\u2019s essential to maintain the same cloud name across different tools for consistency.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/v1759447326\/blog-How_to_Create_an_Image_Text_Overlay_Generator_With_Cloudinary_and_React-4.png\" alt=\"Product Environment. Display name reads DevX Demo.\"\/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Part 2:<strong> <\/strong>Build the React App<\/h2>\n\n\n\n<p>In this tutorial, I\u2019m using <a href=\"https:\/\/vitejs.dev\/guide\/\">Vite<\/a> to build my React application. I recommend that you do the same. Follow the instructions on Vite\u2019s official website to create a React application.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Build the Text Overlay Generator App<\/h3>\n\n\n\n<p>In your <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-TextOverlay-Generator\/blob\/main\/src\/App.tsx\"><strong>App.tsx<\/strong><\/a> file, replace the existing code with the following code. The main purpose of this file is to pass the state to the different components of the app.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React, { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> LeftSideBar <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/LeftSideBar'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> Playground <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/Playground'<\/span>;\n\n<span class=\"hljs-keyword\">export<\/span> interface Settings {\n\n\u00a0\u00a0<span class=\"hljs-attr\">text<\/span>: string;\n\n\u00a0\u00a0fontFamily: string;\n\n\u00a0\u00a0color: string;\n\n\u00a0\u00a0fontSize: number;\n\n\u00a0\u00a0rotation?: number;\n\n\u00a0\u00a0x: number;\n\n\u00a0\u00a0y: number;\n\n\u00a0\u00a0image: string | <span class=\"hljs-literal\">null<\/span>;\n\n}\n\n<span class=\"hljs-keyword\">const<\/span> App: React.FC = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> &#91;settings, setSettings] = useState&lt;Settings&gt;({\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">text<\/span>: <span class=\"hljs-string\">'Cloudinary'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">fontFamily<\/span>: <span class=\"hljs-string\">'Arial'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">color<\/span>: <span class=\"hljs-string\">'#000000'<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">fontSize<\/span>: <span class=\"hljs-number\">30<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">x<\/span>: <span class=\"hljs-number\">0<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-number\">0<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">image<\/span>: <span class=\"hljs-literal\">null<\/span>,\n\n\u00a0\u00a0});\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> &#91;image, setImage] = useState(<span class=\"hljs-string\">''<\/span>)\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> updateSettings = <span class=\"hljs-function\">(<span class=\"hljs-params\">updated: Partial&lt;Settings&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0setSettings(<span class=\"hljs-function\">(<span class=\"hljs-params\">prev<\/span>) =&gt;<\/span> ({\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0...prev,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0...updated,\n\n\u00a0\u00a0\u00a0\u00a0}));\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">LeftSideBar<\/span> <span class=\"hljs-attr\">settings<\/span>=<span class=\"hljs-string\">{settings}<\/span> <span class=\"hljs-attr\">updateSettings<\/span>=<span class=\"hljs-string\">{updateSettings}<\/span> <span class=\"hljs-attr\">setImage<\/span>=<span class=\"hljs-string\">{setImage}<\/span> \/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Playground<\/span> <span class=\"hljs-attr\">settings<\/span>=<span class=\"hljs-string\">{settings}<\/span> <span class=\"hljs-attr\">image<\/span>=<span class=\"hljs-string\">{image}\/<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now, you\u2019ll create a <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-TextOverlay-Generator\/blob\/main\/src\/LeftSideBar.tsx\"><strong>LeftSideBar<\/strong><\/a> component. This component will be in charge of handling the logic for adjusting the settings of the text, including the color, size, position, and font family.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React, { ChangeEvent } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { Settings } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/App'<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> CloudinaryUploadWidget <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/CloudinaryUploadWidget'<\/span>;\n\ninterface LeftSideBarProps {\n\n\u00a0\u00a0<span class=\"hljs-attr\">settings<\/span>: Settings;\n\n\u00a0\u00a0updateSettings: <span class=\"hljs-function\">(<span class=\"hljs-params\">updated: Partial&lt;Settings&gt;<\/span>) =&gt;<\/span> <span class=\"hljs-keyword\">void<\/span>;\n\n\u00a0\u00a0setImage: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;;\n\n}\n\n<span class=\"hljs-keyword\">const<\/span> LeftSideBar: React.FC&lt;LeftSideBarProps&gt; = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ settings, updateSettings, setImage }<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Handlers for the various inputs<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> handleTextChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0updateSettings({ <span class=\"hljs-attr\">text<\/span>: e.target.value });\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> handleFontChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLSelectElement&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0updateSettings({ <span class=\"hljs-attr\">fontFamily<\/span>: e.target.value });\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> handleColorChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0updateSettings({ <span class=\"hljs-attr\">color<\/span>: e.target.value });\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> handleFontSizeChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0updateSettings({ <span class=\"hljs-attr\">fontSize<\/span>: <span class=\"hljs-built_in\">parseInt<\/span>(e.target.value, <span class=\"hljs-number\">10<\/span>) });\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> handleXChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0updateSettings({ <span class=\"hljs-attr\">x<\/span>: <span class=\"hljs-built_in\">parseInt<\/span>(e.target.value, <span class=\"hljs-number\">10<\/span>) });\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> handleYChange = <span class=\"hljs-function\">(<span class=\"hljs-params\">e: ChangeEvent&lt;HTMLInputElement&gt;<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0updateSettings({ <span class=\"hljs-attr\">y<\/span>: <span class=\"hljs-built_in\">parseInt<\/span>(e.target.value, <span class=\"hljs-number\">10<\/span>) });\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"h-screen w-72 p-5 border-r border-gray-300\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-xl font-bold mb-4\"<\/span>&gt;<\/span>Background Text<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h2<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-sm font-medium\"<\/span>&gt;<\/span>Text:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full border border-gray-300 rounded px-2 py-1\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{settings.text}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleTextChange}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-sm font-medium\"<\/span>&gt;<\/span>Font Family:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">select<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full border border-gray-300 rounded px-2 py-1\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{settings.fontFamily}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleFontChange}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"Arial\"<\/span>&gt;<\/span>Arial<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"Times New Roman\"<\/span>&gt;<\/span>Times New Roman<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"Courier New\"<\/span>&gt;<\/span>Courier New<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"Georgia\"<\/span>&gt;<\/span>Georgia<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">option<\/span> <span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">\"Verdana\"<\/span>&gt;<\/span>Verdana<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">option<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">select<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-sm font-medium\"<\/span>&gt;<\/span>Color:<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"color\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full h-10\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{settings.color}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleColorChange}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-sm font-medium\"<\/span>&gt;<\/span>Font Size (px):<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"number\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full border border-gray-300 rounded px-2 py-1\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{settings.fontSize}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleFontSizeChange}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-sm font-medium\"<\/span>&gt;<\/span>X Position (px):<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"number\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full border border-gray-300 rounded px-2 py-1\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{settings.x}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleXChange}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block text-sm font-medium\"<\/span>&gt;<\/span>Y Position (px):<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"number\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"w-full border border-gray-300 rounded px-2 py-1\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">value<\/span>=<span class=\"hljs-string\">{settings.y}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onChange<\/span>=<span class=\"hljs-string\">{handleYChange}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"mb-3\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">CloudinaryUploadWidget<\/span> <span class=\"hljs-attr\">setImage<\/span>=<span class=\"hljs-string\">{setImage}<\/span> \/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> LeftSideBar;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Time to create the <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-TextOverlay-Generator\/blob\/main\/src\/CloudinaryUploadWidget.tsx\"><strong>CloudinaryUploadWidget<\/strong><\/a> file. This file will have a component that we\u2019re injecting into the <strong>LeftSideBar<\/strong> component. The purpose of this component is to add the Cloudinary Upload widget for the user to upload images to the Cloudinary cloud. Make sure to enter your cloud name.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { useEffect, useState, useCallback } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\ninterface Props {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">setImage<\/span>: React.Dispatch&lt;React.SetStateAction&lt;string&gt;&gt;;\n\n\u00a0\u00a0}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">CloudinaryUploadWidget<\/span>(<span class=\"hljs-params\">{setImage}: Props<\/span>) <\/span>{\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> &#91;loaded, setLoaded] = useState(<span class=\"hljs-literal\">false<\/span>);\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> uwConfig = {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">\"YOUR CLOUDE NAME\"<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">uploadPreset<\/span>: <span class=\"hljs-string\">\"upload-images\"<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">sources<\/span>: &#91;<span class=\"hljs-string\">\"local\"<\/span>],\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">multiple<\/span>: <span class=\"hljs-literal\">false<\/span>,\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">tags<\/span>: &#91;<span class=\"hljs-string\">\"text-overlay\"<\/span>],\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/**\n\n\u00a0\u00a0\u00a0* Load Cloudinary Upload Widget Script\n\n\u00a0\u00a0\u00a0*\/<\/span>\n\n\u00a0\u00a0useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">if<\/span> (!loaded) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> uwScript = <span class=\"hljs-built_in\">document<\/span>.getElementById(<span class=\"hljs-string\">\"uw\"<\/span>);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">if<\/span> (!uwScript) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> script = <span class=\"hljs-built_in\">document<\/span>.createElement(<span class=\"hljs-string\">\"script\"<\/span>);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0script.setAttribute(<span class=\"hljs-string\">\"async\"<\/span>, <span class=\"hljs-string\">\"\"<\/span>);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0script.setAttribute(<span class=\"hljs-string\">\"id\"<\/span>, <span class=\"hljs-string\">\"uw\"<\/span>);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0script.src = <span class=\"hljs-string\">\"https:\/\/upload-widget.cloudinary.com\/global\/all.js\"<\/span>;\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0script.addEventListener(<span class=\"hljs-string\">\"load\"<\/span>, () =&gt; setLoaded(<span class=\"hljs-literal\">true<\/span>));\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-built_in\">document<\/span>.body.appendChild(script);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} <span class=\"hljs-keyword\">else<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setLoaded(<span class=\"hljs-literal\">true<\/span>);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0}, &#91;loaded]);\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> initializeCloudinaryWidget = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">if<\/span> (loaded) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">try<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-built_in\">window<\/span>.cloudinary.openUploadWidget(uwConfig, processUploads);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} <span class=\"hljs-keyword\">catch<\/span> (error) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">\"failed\"<\/span>, error);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0};\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> processUploads = useCallback(<span class=\"hljs-function\">(<span class=\"hljs-params\">error, result<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">if<\/span> (result?.event === <span class=\"hljs-string\">\"queues-end\"<\/span>) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-built_in\">console<\/span>.log(<span class=\"hljs-string\">'result'<\/span>, result.info.files&#91;<span class=\"hljs-number\">0<\/span>].name);\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setImage(result.info.files&#91;<span class=\"hljs-number\">0<\/span>].name <span class=\"hljs-keyword\">as<\/span> string);\n\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0}, &#91;]);\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"upload_widget\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-blue-600 text-white hover:bg-blue-200 hover:text-black cursor-pointer h-&#91;40px] rounded-lg w-full flex justify-center items-center \"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{initializeCloudinaryWidget}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Upload Image\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> CloudinaryUploadWidget;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Finally, we\u2019ll create the <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-TextOverlay-Generator\/blob\/main\/src\/Playground.tsx\"><strong>Playground<\/strong><\/a> component. This component will put all the pieces together using Cloudinary transformations. The way it works is, we have two copies of the same image and we stack them one on top of the other. The one on top will be converted into a PNG, and we\u2019ll remove the background. Now, between these two images, we\u2019ll add the text so the image has a nice 2D effect. Make sure to change the cloud name when initializing Cloudinary.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> React, { useRef, useMemo } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { Settings } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/App\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { Cloudinary } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { AdvancedImage } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/react\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { backgroundRemoval } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/actions\/effect\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { source } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/actions\/overlay\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { text <span class=\"hljs-keyword\">as<\/span> cloudinaryText } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/qualifiers\/source\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { TextStyle } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/qualifiers\/textStyle\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { Position } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/qualifiers\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { compass } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/qualifiers\/gravity\"<\/span>;\n\n<span class=\"hljs-keyword\">import<\/span> { fetch } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@cloudinary\/url-gen\/qualifiers\/source\"<\/span>;\n\ninterface PlaygroundProps {\n\n\u00a0\u00a0<span class=\"hljs-attr\">settings<\/span>: Settings;\n\n\u00a0\u00a0image: string;\n\n}\n\n<span class=\"hljs-keyword\">const<\/span> Playground: React.FC&lt;PlaygroundProps&gt; = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ settings, image }<\/span>) =&gt;<\/span> {\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> containerRef = useRef&lt;HTMLDivElement&gt;(<span class=\"hljs-literal\">null<\/span>);\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ 1) Only initialize Cloudinary once<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> cld = useMemo(\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">new<\/span> Cloudinary({\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">cloud<\/span>: { <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">\"text-overlay\"<\/span> },\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}),\n\n\u00a0\u00a0\u00a0\u00a0&#91;]\n\n\u00a0\u00a0);\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ 2) Create the \u201ctop\u201d image pipeline (background removal) separately<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> topImage = useMemo(\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0cld\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.image(image)\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.effect(backgroundRemoval().fineEdges())\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.format(<span class=\"hljs-string\">\"png\"<\/span>),\n\n\u00a0\u00a0\u00a0\u00a0&#91;cld, image]\n\n\u00a0\u00a0);\n\n\u00a0\u00a0<span class=\"hljs-comment\">\/\/ 3) Create a fresh \u201cbackground + text overlay\u201d pipeline on every relevant change<\/span>\n\n\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> backgroundWithText = useMemo(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">const<\/span> img = cld.image(image);\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-comment\">\/\/ Apply overlay only if there\u2019s text<\/span>\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">if<\/span> (settings.text) {\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0img.overlay(\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0source(\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0cloudinaryText(\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0settings.text,\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">new<\/span> TextStyle(settings.fontFamily, settings.fontSize)\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0).textColor(settings.color)\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0).position(\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">new<\/span> Position()\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.gravity(compass(<span class=\"hljs-string\">\"north_west\"<\/span>))\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.offsetX(<span class=\"hljs-built_in\">Math<\/span>.round(settings.x))\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0.offsetY(<span class=\"hljs-built_in\">Math<\/span>.round(settings.y))\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0).overlay(source(fetch(\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0topImage.toURL()\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)));\n\n\u00a0\u00a0\u00a0\u00a0}\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> img;\n\n\u00a0\u00a0}, &#91;\n\n\u00a0\u00a0\u00a0\u00a0cld,\n\n\u00a0\u00a0\u00a0\u00a0image,\n\n\u00a0\u00a0\u00a0\u00a0settings.text,\n\n\u00a0\u00a0\u00a0\u00a0settings.fontFamily,\n\n\u00a0\u00a0\u00a0\u00a0settings.fontSize,\n\n\u00a0\u00a0\u00a0\u00a0settings.color,\n\n\u00a0\u00a0\u00a0\u00a0settings.x,\n\n\u00a0\u00a0\u00a0\u00a0settings.y,\n\n\u00a0\u00a0\u00a0\u00a0topImage\n\n\u00a0\u00a0]);\n\n\u00a0\u00a0<span class=\"hljs-keyword\">return<\/span> (\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"flex-1 p-5 flex justify-center items-center flex-col gap-4\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{image ? (\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{containerRef}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"relative inline-block overflow-hidden\"<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">AdvancedImage<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">cldImg<\/span>=<span class=\"hljs-string\">{backgroundWithText}<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"Background with Text\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"block max-w-full h-auto\"<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0) : (\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-gray-500\"<\/span>&gt;<\/span>Please upload an image.<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0)}\n\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0{ image &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{backgroundWithText.toURL()}<\/span> <span class=\"hljs-attr\">target<\/span>=<span class=\"hljs-string\">\"_blank\"<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"bg-blue-600 text-white hover:bg-blue-200 hover:text-black cursor-pointer h-&#91;40px] rounded-lg w-&#91;200px] flex justify-center items-center\"<\/span>&gt;<\/span>Download Image<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>}\n\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n\n\u00a0\u00a0);\n\n};\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> Playground;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<h2 class=\"wp-block-heading\">Part 3: Test the App<\/h2>\n\n\n\n<p>The first thing we have to do is to run<strong> npm install <\/strong>in the root of your project to install the frontend and backend dependencies.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Run the Frontend Server<\/h3>\n\n\n\n<p>Open your other terminal, run <strong>npm run dev<\/strong>,<strong> <\/strong>and navigate to <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>You now have a working React image text overlay tool powered by Cloudinary, where users can upload, edit, and preview production-ready assets in real time. With the heavy lifting handled by Cloudinary, you can focus on extending features and building creative experiences faster.<\/p>\n\n\n\n<p>To stay updated with the latest product features, follow <a href=\"https:\/\/twitter.com\/cloudinary\">Cloudinary<\/a> on X and explore other <a href=\"https:\/\/github.com\/cloudinary-community\">sample apps<\/a>.<\/p>\n\n\n\n<p>Building an app with Cloudinary and need inspiration? Visit the <a href=\"https:\/\/app-gallery.cloudinary.com\/\">App Gallery<\/a>.<\/p>\n\n\n\n<p><strong>Resources:<\/strong><\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>GitHub Repo: <a href=\"https:\/\/github.com\/cloudinary-devs\/Cloudinary-TextOverlay-Generator\">Cloudinary-Text-Overlay-Generator<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered by Cloudinary. Users will upload an image straight to Cloudinary, then layer editable text, adjust its reposition, resize, tweak styling, and see instant previews driven by Cloudinary\u2019s on-the-fly transformations. We\u2019ll [&hellip;]<\/p>\n","protected":false},"author":87,"featured_media":38695,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[165,246],"class_list":["post-38691","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-image-transformation","tag-react"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>How to Create an Image Text Overlay Generator With Cloudinary and React<\/title>\n<meta name=\"description\" content=\"Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Create an Image Text Overlay Generator With Cloudinary and React\" \/>\n<meta property=\"og:description\" content=\"Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-02T14:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-10-03T16:20:15+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"1100\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"melindapham\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\"},\"author\":{\"name\":\"melindapham\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\"},\"headline\":\"How to Create an Image Text Overlay Generator With Cloudinary and React\",\"datePublished\":\"2025-10-02T14:00:00+00:00\",\"dateModified\":\"2025-10-03T16:20:15+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\"},\"wordCount\":577,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA\",\"keywords\":[\"Image Transformation\",\"React\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2025\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\",\"url\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\",\"name\":\"How to Create an Image Text Overlay Generator With Cloudinary and React\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA\",\"datePublished\":\"2025-10-02T14:00:00+00:00\",\"dateModified\":\"2025-10-03T16:20:15+00:00\",\"description\":\"Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA\",\"width\":2000,\"height\":1100},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Create an Image Text Overlay Generator With Cloudinary and React\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9\",\"name\":\"melindapham\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g\",\"caption\":\"melindapham\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"How to Create an Image Text Overlay Generator With Cloudinary and React","description":"Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react","og_locale":"en_US","og_type":"article","og_title":"How to Create an Image Text Overlay Generator With Cloudinary and React","og_description":"Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered","og_url":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react","og_site_name":"Cloudinary Blog","article_published_time":"2025-10-02T14:00:00+00:00","article_modified_time":"2025-10-03T16:20:15+00:00","og_image":[{"width":2000,"height":1100,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA","type":"image\/jpeg"}],"author":"melindapham","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react"},"author":{"name":"melindapham","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9"},"headline":"How to Create an Image Text Overlay Generator With Cloudinary and React","datePublished":"2025-10-02T14:00:00+00:00","dateModified":"2025-10-03T16:20:15+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react"},"wordCount":577,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA","keywords":["Image Transformation","React"],"inLanguage":"en-US","copyrightYear":"2025","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react","url":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react","name":"How to Create an Image Text Overlay Generator With Cloudinary and React","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA","datePublished":"2025-10-02T14:00:00+00:00","dateModified":"2025-10-03T16:20:15+00:00","description":"Want to ship a quick banner maker without wrangling a custom canvas stack? In this post, you\u2019ll build a React-based image text overlay generator powered","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA","width":2000,"height":1100},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/image-text-overlay-generator-react#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Create an Image Text Overlay Generator With Cloudinary and React"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/0d5ad601e4c3b5be89245dfb14be42d9","name":"melindapham","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/e6f989fa97fe94be61596259d8629c3df65aec4c7da5c0000f90d810f313d4f4?s=96&d=mm&r=g","caption":"melindapham"}}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1759340723\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React\/Blog_How_To_Create_An_Image_Text_Overlay_Generator_With_Cloudinary_and_React.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/38691","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/87"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=38691"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/38691\/revisions"}],"predecessor-version":[{"id":38697,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/38691\/revisions\/38697"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/38695"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=38691"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=38691"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=38691"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}