{"id":28195,"date":"2022-03-24T20:16:02","date_gmt":"2022-03-24T20:16:02","guid":{"rendered":"http:\/\/Add-Drag-and-Drop-for-Media-Files-with-React-(12)"},"modified":"2025-02-09T12:26:25","modified_gmt":"2025-02-09T20:26:25","slug":"add-drag-and-drop-for-media-files-with-react-12","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/","title":{"rendered":"Add Drag and Drop for Images with React (1\/2)"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>As the world becomes increasingly interconnected, file sharing and exchange (mainly images) are becoming more prevalent. As a result, particular care must be taken in making the process as easy as possible.<\/p>\n<p>This is the first part of a two-part series. In this post, we\u2019ll look at how to add drag and drop functionality for media files to a React application, allowing you to select multiple images at once and, not only that, preview the selected images before uploading. Before uploading, you will also have the opportunity to delete an image if you wish to.<\/p>\n<p>Here\u2019s a <a href=\"https:\/\/codesandbox.io\/s\/drag-and-drop-with-ant-design-qjl5r\">link<\/a> to the demo on CodeSandbox.<\/p>\n<\/div>\n\n\n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/drag-and-drop-with-ant-design-qjl5r?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"drag-and-drop-with-ant-design-qjl5r\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n\n<div class=\"wp-block-cloudinary-markdown \"><h2>Project Setup<\/h2>\n<p>Create a new React app using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npx create-react-app drag_and_drop_demo\n<\/code><\/span><\/pre>\n<p>Next, let\u2019s add the project dependencies. We will be using <a href=\"https:\/\/ant.design\/\">Ant Design<\/a> to render our UI components for this project. Add it to your project using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">    <span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">i<\/span> <span class=\"hljs-selector-tag\">antd<\/span> <span class=\"hljs-keyword\">@ant-design<\/span>\/icons\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, we need to import the antd CSS. To do this, open <code>src\/App.css<\/code> and edit its content to match the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">    <span class=\"hljs-keyword\">@import<\/span> <span class=\"hljs-string\">'~antd\/dist\/antd.css'<\/span>;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Implement Drag and Drop Functionality<\/h2>\n<h3>Create useFileSelection Hook<\/h3>\n<p>To keep our components lean and focused on presentation, we\u2019ll use hooks to inject the needed functionality into the component. In the <code>src<\/code> folder, create a new folder called <code>hooks<\/code>. This folder will hold the hooks we will create in this app &#8211; one for the drag and drop functionality and the other for preview.<\/p>\n<p>In the <code>src\/hooks<\/code> folder, create a new file called <code>useFileSelection.js<\/code> and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" 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> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> useFileSelection = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> &#91;selectedFiles, setSelectedFiles] = useState(&#91;]);\n      <span class=\"hljs-keyword\">const<\/span> addFile = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> {\n        setSelectedFiles(<span class=\"hljs-function\">(<span class=\"hljs-params\">currentSelection<\/span>) =&gt;<\/span> &#91;...currentSelection, file]);\n      };\n      <span class=\"hljs-keyword\">const<\/span> removeFile = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> {\n        setSelectedFiles(<span class=\"hljs-function\">(<span class=\"hljs-params\">currentSelection<\/span>) =&gt;<\/span> {\n          <span class=\"hljs-keyword\">const<\/span> newSelection = currentSelection.slice();\n          <span class=\"hljs-keyword\">const<\/span> fileIndex = currentSelection.indexOf(file);\n          newSelection.splice(fileIndex, <span class=\"hljs-number\">1<\/span>);\n          <span class=\"hljs-keyword\">return<\/span> newSelection;\n        });\n      };\n      <span class=\"hljs-keyword\">return<\/span> &#91;addFile, removeFile];\n    };\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> useFileSelection;\n<\/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<p>We start by declaring a state variable for the selected files. Since we will be dealing with more than one file in the selection, we initialized it with an empty array.<\/p>\n<p>Next, we declare a function named <code>addFile<\/code> to add a file to the array of selected files. The function takes a file and adds it to the currently selected files by using the <code>setSelectedFiles<\/code> function to update the state.<\/p>\n<p>We also want to be able to remove a file from the list of selected files, so we declare a function named <code>removeFile<\/code>, which accepts the file to be removed as a parameter. In the <code>setSelectedFiles<\/code> function call, we pass a function that takes the selected files in state and does the following:<\/p>\n<ol>\n<li>Creates a shallow copy of the current selection of files using the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/slice\">slice<\/a> function.<\/li>\n<li>Gets the index of the provided file in the current selection of files.<\/li>\n<li>Removes the file from the shallow copy using the <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Array\/splice\">splice<\/a> function.<\/li>\n<li>Returns the new selection with the file removed.<\/li>\n<\/ol>\n<p>Finally, we return an array containing the <code>addFile<\/code> and <code>removeFile<\/code> functions.<\/p>\n<h3>Create useFilePreview Hook<\/h3>\n<p>In the <code>src\/hooks<\/code> folder, create a new file named <code>useFilePreview.js<\/code> and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" 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> { Modal } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'antd'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> useFilePreview = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> &#91;previewVisibility, setPreviewVisibility] = useState(<span class=\"hljs-literal\">false<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;previewImage, setPreviewImage] = useState(<span class=\"hljs-literal\">null<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;previewTitle, setPreviewTitle] = useState(<span class=\"hljs-string\">''<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> getBase64Representation = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span>\n        <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Promise<\/span>(<span class=\"hljs-function\">(<span class=\"hljs-params\">resolve, reject<\/span>) =&gt;<\/span> {\n          <span class=\"hljs-keyword\">const<\/span> reader = <span class=\"hljs-keyword\">new<\/span> FileReader();\n          reader.readAsDataURL(file);\n          reader.onload = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> resolve(reader.result);\n          reader.onerror = <span class=\"hljs-function\">(<span class=\"hljs-params\">error<\/span>) =&gt;<\/span> reject(error);\n        });\n      <span class=\"hljs-keyword\">const<\/span> handlePreview = <span class=\"hljs-keyword\">async<\/span> (file) =&gt; {\n        <span class=\"hljs-keyword\">if<\/span> (!file.url &amp;&amp; !file.preview) {\n          file.preview = <span class=\"hljs-keyword\">await<\/span> getBase64Representation(file.originFileObj);\n        }\n        setPreviewImage(file.url || file.preview);\n        setPreviewVisibility(<span class=\"hljs-literal\">true<\/span>);\n        setPreviewTitle(\n          file.name || file.url.substring(file.url.lastIndexOf(<span class=\"hljs-string\">'\/'<\/span>) + <span class=\"hljs-number\">1<\/span>)\n        );\n      };\n      <span class=\"hljs-keyword\">const<\/span> hidePreview = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n        setPreviewVisibility(<span class=\"hljs-literal\">false<\/span>);\n      };\n      <span class=\"hljs-keyword\">const<\/span> previewContent = (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Modal<\/span>\n          <span class=\"hljs-attr\">visible<\/span>=<span class=\"hljs-string\">{previewVisibility}<\/span>\n          <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">{previewTitle}<\/span>\n          <span class=\"hljs-attr\">footer<\/span>=<span class=\"hljs-string\">{null}<\/span>\n          <span class=\"hljs-attr\">onCancel<\/span>=<span class=\"hljs-string\">{hidePreview}<\/span>\n        &gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{previewTitle}<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">width:<\/span> '<span class=\"hljs-attr\">100<\/span>%' }} <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{previewImage}<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Modal<\/span>&gt;<\/span><\/span>\n      );\n      <span class=\"hljs-keyword\">return<\/span> &#91;handlePreview, previewContent];\n    };\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> useFilePreview;\n<\/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<p>In this hook, we declare three state variables. <code>previewVisibility<\/code> is a boolean that determines whether the image preview should be rendered. <code>previewImage<\/code> contains the base64 representation of the image to be previewed, while <code>previewTitle<\/code> contains the title of the preview, which is the name of the file to be previewed.<\/p>\n<p>Next, we declare a function named <code>getBase64Representation<\/code> which takes a file and returns its <code>base64<\/code> representation.<\/p>\n<p>After this, we declare an asynchronous function named <code>handlePreview<\/code> which takes a file and updates the preview image, title, and visibility in state. By setting the visibility to true, the preview will be rendered and displayed to the user.<\/p>\n<p>The user should also have the option to close the preview. The <code>hidePreview<\/code> function handles this by setting the visibility in state to <code>false<\/code>, causing the preview to be hidden. Next, we declare the JSX for the preview. The preview is essentially an image wrapped in a <a href=\"https:\/\/ant.design\/components\/modal\/\">Modal<\/a> component. Using the title and image stored in state, we update the relevant props for the preview component. Finally, we return an array containing the <code>handlePreview<\/code> function and <code>previewContent<\/code> constant.<\/p>\n<p>With the hooks in place, we can create the components for our application. In the <code>src<\/code> folder, create a new folder called <code>components<\/code>.<\/p>\n<h2>Create DragAndDrop Component<\/h2>\n<p>In the <code>src\/components<\/code> directory, create a new file called <code>DragAndDrop.js<\/code> and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" 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> { Upload } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'antd'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { PlusOutlined } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@ant-design\/icons'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> useFilePreview <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'..\/hooks\/useFilePreview'<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> { Dragger } = Upload;\n    <span class=\"hljs-keyword\">const<\/span> DragAndDrop = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ addFile, removeFile }<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> &#91;handlePreview, previewContent] = useFilePreview();\n      <span class=\"hljs-keyword\">const<\/span> beforeUploadHandler = <span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span> {\n        addFile(file);\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n      };\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Dragger<\/span>\n            <span class=\"hljs-attr\">multiple<\/span>=<span class=\"hljs-string\">{true}<\/span>\n            <span class=\"hljs-attr\">onRemove<\/span>=<span class=\"hljs-string\">{removeFile}<\/span>\n            <span class=\"hljs-attr\">showUploadList<\/span>=<span class=\"hljs-string\">{true}<\/span>\n            <span class=\"hljs-attr\">listType<\/span>=<span class=\"hljs-string\">\"picture-card\"<\/span>\n            <span class=\"hljs-attr\">beforeUpload<\/span>=<span class=\"hljs-string\">{beforeUploadHandler}<\/span>\n            <span class=\"hljs-attr\">onPreview<\/span>=<span class=\"hljs-string\">{handlePreview}<\/span>\n            <span class=\"hljs-attr\">accept<\/span>=<span class=\"hljs-string\">\"image\/*\"<\/span>\n          &gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"ant-upload-drag-icon\"<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">PlusOutlined<\/span> \/&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"ant-upload-text\"<\/span>&gt;<\/span>\n              Click this area or drag files to upload\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Dragger<\/span>&gt;<\/span>\n          {previewContent}\n        <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n      );\n    };\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> DragAndDrop;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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<p>The <code>DragAndDrop<\/code> component takes two props &#8211; <code>addFile<\/code> and <code>removeFile<\/code>. These will be used to update the selection of files in state. The functionality and JSX to render previews of uploaded images are retrieved from the <code>useFilePreview<\/code> hook.<\/p>\n<p>The <code>beforeUploadHandler<\/code> function takes a file and adds it to the selection in state. This function is passed as a prop to override the default behavior of the <a href=\"https:\/\/ant.design\/components\/upload\/\">Upload<\/a> component when a file is added. By returning <code>false<\/code>, we disable the default behavior of uploading the selected file to a provided URL.<\/p>\n<p>Finally, we return the JSX for the <code>DragAndDrop<\/code> component. Antd provides a <code>Dragger<\/code> component as part of the <code>Upload<\/code> component. Because we want to upload multiple images at once, we pass <code>true<\/code> for the <code>multiple<\/code> prop. We also restrict the accepted file type to images using the <code>accept<\/code> prop. The <code>showUploadList<\/code> and <code>list-type<\/code> props let the component know that we want to display the uploaded images as a list with <code>picture-card<\/code>, causing the list to be displayed as a grid of thumbnail images. We also include the JSX for the image preview (retrieved from the <code>useFilePreview<\/code> hook) under the <code>Dragger<\/code> component.<\/p>\n<h2>Putting It All Together<\/h2>\n<p>Update your <code>src\/App.js<\/code> file to match the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" 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> <span class=\"hljs-string\">'.\/App.css'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { Button, Card } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'antd'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> DragAndDrop <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/components\/DragAndDrop'<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> useFileSelection <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'.\/hooks\/useFileSelection'<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> App = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> &#91;addFile, removeFile] = useFileSelection();\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">margin:<\/span> '<span class=\"hljs-attr\">1<\/span>%' }}&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Card<\/span>\n            <span class=\"hljs-attr\">style<\/span>=<span class=\"hljs-string\">{{<\/span> <span class=\"hljs-attr\">margin:<\/span> '<span class=\"hljs-attr\">auto<\/span>', <span class=\"hljs-attr\">width:<\/span> '<span class=\"hljs-attr\">50<\/span>%' }}\n            <span class=\"hljs-attr\">actions<\/span>=<span class=\"hljs-string\">{&#91;<\/span>&lt;<span class=\"hljs-attr\">Button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"primary\"<\/span>&gt;<\/span>Submit<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Button<\/span>&gt;<\/span>]}\n          &gt;\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">DragAndDrop<\/span> <span class=\"hljs-attr\">addFile<\/span>=<span class=\"hljs-string\">{addFile}<\/span> <span class=\"hljs-attr\">removeFile<\/span>=<span class=\"hljs-string\">{removeFile}<\/span> \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Card<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n      );\n    };\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> App;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><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<p>In the App component, we retrieve the <code>addFile<\/code> and <code>removeFile<\/code> functions from the <code>useFileSelection<\/code> hook, which we pass as props to the <code>DragAndDrop<\/code> component. We wrap the <code>DragAndDrop<\/code> component in a <a href=\"https:\/\/ant.design\/components\/card\/\">Card<\/a> component. We also include a <code>button<\/code> in the card, which will be used to submit (upload) the selected files.<\/p>\n<p>Run this command to spin up a local development server:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npm start\n<\/code><\/span><\/pre>\n<p>By default, the application will be available at <a href=\"http:\/\/localhost:3000\/\">http:\/\/localhost:3000\/<\/a>. When you upload some images, the final result should look like the image below:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_58E22D55AF9776C251BA9C9EFC92BDB26BC16B4AFED7CCBB77FBA4C1DD5C663C_1644773730832_CleanShot+2022-02-13+at+21.35.072x.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"862\"\/><\/p>\n<p>Find the complete project <a href=\"https:\/\/github.com\/ifeoma-imoh\/drag-and-drop-demo\">here<\/a> on GitHub.<\/p>\n<h2>Conclusion<\/h2>\n<p>In this article, we saw how to take advantage of Antd to create a visually appealing component that eases the process of uploading multiple images via the drag and drop functionality. In the next part of this series, we\u2019ll take things a step further by uploading multiple files to <a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a> at once.<\/p>\n<h3>Here are some resources you may find helpful:<\/h3>\n<ul>\n<li>\n<a href=\"https:\/\/ant.design\/\">Ant Design Documentation<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/reactjs.org\/\">React.js Documentation<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/HTML_Drag_and_Drop_API\">HTML Drag and Drop API<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28196,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,246,371,373],"class_list":["post-28195","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-react","tag-under-review","tag-upload"],"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>Add Drag and Drop for Images with React (1\/2)<\/title>\n<meta name=\"description\" content=\"In this post, we&#039;ll look at how to add drag and drop functionality for media files to a React app, allowing you to select multiple images at once and preview them before uploading.\" \/>\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\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Add Drag and Drop for Images with React (1\/2)\" \/>\n<meta property=\"og:description\" content=\"In this post, we&#039;ll look at how to add drag and drop functionality for media files to a React app, allowing you to select multiple images at once and preview them before uploading.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-24T20:16:02+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-02-09T20:26:25+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991-png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"720\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\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\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Add Drag and Drop for Images with React (1\/2)\",\"datePublished\":\"2022-03-24T20:16:02+00:00\",\"dateModified\":\"2025-02-09T20:26:25+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/\"},\"wordCount\":8,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"React\",\"Under Review\",\"Upload\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\",\"name\":\"Add Drag and Drop for Images with React (1\/2)\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA\",\"datePublished\":\"2022-03-24T20:16:02+00:00\",\"dateModified\":\"2025-02-09T20:26:25+00:00\",\"description\":\"In this post, we'll look at how to add drag and drop functionality for media files to a React app, allowing you to select multiple images at once and preview them before uploading.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA\",\"width\":1280,\"height\":720},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Add Drag and Drop for Images with React (1\/2)\"}]},{\"@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\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Add Drag and Drop for Images with React (1\/2)","description":"In this post, we'll look at how to add drag and drop functionality for media files to a React app, allowing you to select multiple images at once and preview them before uploading.","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\/guest_post\/add-drag-and-drop-for-media-files-with-react-12","og_locale":"en_US","og_type":"article","og_title":"Add Drag and Drop for Images with React (1\/2)","og_description":"In this post, we'll look at how to add drag and drop functionality for media files to a React app, allowing you to select multiple images at once and preview them before uploading.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-24T20:16:02+00:00","article_modified_time":"2025-02-09T20:26:25+00:00","og_image":[{"width":1280,"height":720,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991-png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/"},"author":{"name":"","@id":""},"headline":"Add Drag and Drop for Images with React (1\/2)","datePublished":"2022-03-24T20:16:02+00:00","dateModified":"2025-02-09T20:26:25+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/"},"wordCount":8,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA","keywords":["Guest Post","Image","React","Under Review","Upload"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12","name":"Add Drag and Drop for Images with React (1\/2)","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA","datePublished":"2022-03-24T20:16:02+00:00","dateModified":"2025-02-09T20:26:25+00:00","description":"In this post, we'll look at how to add drag and drop functionality for media files to a React app, allowing you to select multiple images at once and preview them before uploading.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA","width":1280,"height":720},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/add-drag-and-drop-for-media-files-with-react-12#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Add Drag and Drop for Images with React (1\/2)"}]},{"@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":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925149\/Web_Assets\/blog\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991\/01fc0276f1fcdab55f17799c141cf31858334e95-1280x720-1_28196fe991.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28195","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\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28195"}],"version-history":[{"count":2,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28195\/revisions"}],"predecessor-version":[{"id":36776,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28195\/revisions\/36776"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28196"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}