{"id":28330,"date":"2022-04-28T14:40:14","date_gmt":"2022-04-28T14:40:14","guid":{"rendered":"http:\/\/implement-drag-and-drop-for-media-upload-with-react"},"modified":"2022-04-28T14:40:14","modified_gmt":"2022-04-28T14:40:14","slug":"implement-drag-and-drop-for-media-upload-with-react","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/","title":{"rendered":"Implement Drag and Drop for Media Upload in React"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Media uploading has transitioned from conventional clicking and uploading to drag and drop functionality. Most companies are now moving to this new trend for a better user experience. In this tutorial, we will be implementing a drag and drop functionality in a react application.<\/p>\n<h2>Setup<\/h2>\n<p>First, we need to create our react application. To do that, Make sure you have <a href=\"https:\/\/nodejs.org\/en\/\">Nodejs<\/a> and npm installed then paste the code below into the terminal.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npx create-react-app media-upload\n<\/code><\/span><\/pre>\n<p>Install the react-dropzone package, which will help us implement the drag and drop functionality.  To install the package, run the code below.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npm install react-dropzone\n<\/code><\/span><\/pre>\n<h2>Create a Dropzone<\/h2>\n<p>After setting up our project and installing the <code>react-dropzone<\/code> package, the next is to import the package into our App.js. We will be importing the <code>useDropzone<\/code> hook from the package and calling it inside our component. To do that, paste the code snippet below.<\/p>\n<pre class=\"js-syntax-highlighted\" 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 <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> { useDropzone } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'react-dropzone'<\/span>;\n    \n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n<span class=\"hljs-keyword\">const<\/span> {\n  getRootProps,\n  getInputProps,\n  isDragActive,\n} = useDropzone({ onDrop });\n    \n<span class=\"hljs-keyword\">return<\/span> (\n       ...\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-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<p><code>useDropZone<\/code> hook gives us access to the properties for handling dropping a file. It also takes a config object, and one of the properties in the config object is the onDrop function called after the file is dropped in the dropzone.<\/p>\n<p><code>useDropZone<\/code> returns  <code>getRootProps<\/code>, <code>getInputProps<\/code>, <code>isDragActive<\/code> which we can call to get the Drag and Drop API properties and pass those to our elements.<\/p>\n<p>This is what the dropzone input and root should look like:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> {<span class=\"hljs-attr\">...getRootProps<\/span>()}&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> {<span class=\"hljs-attr\">...getInputProps<\/span>()} \/&gt;<\/span>\n    <span class=\"hljs-comment\">&lt;!-- Any content you want to show on the drop zone --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/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\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The <code>getRootProps<\/code> sets drag and drop API properties on the chosen root. Here is what the properties look like:<\/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_4CA84BEC8104DB0528B5052503E40960C013D2636C1D45C53DFAB16CD81B995E_1645521097728_image.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1208\" height=\"386\"\/><\/p>\n<p>These events allow your browser to listen to users\u2019 drag and drop interactions.<\/p>\n<p>The <code>getInputProps<\/code> is like <code>getRootProps<\/code> but attaches events and properties to an input. It will do things like setting the input type to file and also attaching the <code>onChange<\/code> event handler. Here are the properties:<\/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_4CA84BEC8104DB0528B5052503E40960C013D2636C1D45C53DFAB16CD81B995E_1645521232850_image.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1190\" height=\"334\"\/><\/p>\n<p>The <code>isDragActive<\/code> is a boolean value that is true if we are dragging a file over the Dropzone but false if not. To add the <code>isDragActive<\/code> function paste the code below in after the input tag.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">{isDragActive ? (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-center text-xl\"<\/span>&gt;<\/span>Drop your media files here<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n) : (\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"text-center text-xl\"<\/span>&gt;<\/span>\n    Drag and drop some files here, or click to select files\n  <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now that we have added the <code>useDropZone<\/code> properties to our JSX. we will define our callback function. Remember we mentioned that <code>onDrop<\/code> is the callback function called when a file is dropped on the drop zone. Paste the code below to define the function.<\/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\">const<\/span> onDrop = React.useCallback(<span class=\"hljs-function\">(<span class=\"hljs-params\">acceptedFiles<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-built_in\">console<\/span>.log(acceptedFiles);\n}, &#91;]);\n    \n<span class=\"hljs-keyword\">const<\/span> {\n  getRootProps,\n  getInputProps,\n  isDragActive,\n} = useDropzone({ onDrop });\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>The <code>onDrop<\/code> function passed to the hook receives an argument containing the information about the updated file. Here, we can upload the file to a cloud, preview the file, and more. Wrapped the function with <code>useCallback<\/code> to ensure that it does not trigger unnecessary re-renders.<\/p>\n<h2>How to add extra properties to the drop zone<\/h2>\n<p>Suppose we want to set props on elements with either the <code>getRootProps<\/code> or <code>getInputProps<\/code>. In that case, we need to put them as an argument to those functions to avoid overriding things unexpectedly.<\/p>\n<p>So instead of this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> {<span class=\"hljs-attr\">...getRootProps<\/span>()} <span class=\"hljs-attr\">role<\/span>=<span class=\"hljs-string\">\"button\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> {<span class=\"hljs-attr\">...getInputProps<\/span>()} \/&gt;<\/span>\n    <span class=\"hljs-comment\">&lt;!-- Any content you want to show on the drop zone --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Do this:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> {<span class=\"hljs-attr\">...getRootProps<\/span>({\n  <span class=\"hljs-attr\">role:<\/span> '<span class=\"hljs-attr\">button<\/span>'\n})}&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span> {<span class=\"hljs-attr\">...getInputProps<\/span>()} \/&gt;<\/span>\n    <span class=\"hljs-comment\">&lt;!-- Any content you want to show on the drop zone --&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<h2>Validate the Dropped Files<\/h2>\n<p>The <code>useDropzone<\/code> has some predefined props for validations. It has the accept props, maxFiles props, and many others. It can also accept a defined validation function as props if we choose not to use the predefined functions. The accept props disallows files not included in the <code>accept<\/code> list. Hence we can only select files that are listed. In the snippet below, we can only upload png and jpeg files.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">useDropzone<\/span>({\n  <span class=\"hljs-attribute\">accept<\/span>: <span class=\"hljs-string\">'image\/jpeg,image\/png'<\/span>\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><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><code>maxFiles<\/code>  defines the maximum number of files that can be uploaded. If the validation fails, we will get an empty array in the <code>onDrop<\/code> callback.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">useDropzone<\/span>({    \n  <span class=\"hljs-attribute\">maxFiles<\/span>: <span class=\"hljs-number\">2<\/span>\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><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>To show the actual error, we can inspect the <code>fileRejections<\/code> from <code>useDropzone<\/code>.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> {\n  fileRejections, <span class=\"hljs-comment\">\/\/ Error files<\/span>\n  getRootProps,\n  getInputProps,\n  isDragActive,\n} = useDropzone({\n  onDrop,\n  <span class=\"hljs-attr\">accept<\/span>: <span class=\"hljs-string\">'image\/jpeg,image\/png'<\/span>,\n  <span class=\"hljs-attr\">maxFiles<\/span>: <span class=\"hljs-number\">2<\/span>,\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><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>To display the error message using the <code>fileRejections<\/code> ,You can iterate through the rejected files and render the errors.<\/p>\n<p>Paste the code below to display the errors:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">{fileRejections.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">{ file, errors }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{file.path}<\/span>&gt;<\/span>\n      {file.path} - {file.size} bytes\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n        {errors.map((e) =&gt; (\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{e.code}<\/span>&gt;<\/span>{e.message}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n        ))}\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span><\/span>\n  );\n})}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><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><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_4CA84BEC8104DB0528B5052503E40960C013D2636C1D45C53DFAB16CD81B995E_1645522623692_image.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1152\" height=\"852\"\/><\/p>\n<p>We can also do all sorts of flexible and custom  validations and not just limited to what is allowed as an argument to the <code>useDropzone<\/code> hook. Here is an example showing how to validate for max size for each file:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ Validate that the file size is less than 2mb<\/span>\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">fileSizeValidator<\/span>(<span class=\"hljs-params\">file<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">if<\/span> (file.size &gt; <span class=\"hljs-number\">1024<\/span> ** <span class=\"hljs-number\">2<\/span> * <span class=\"hljs-number\">2<\/span>) {\n    <span class=\"hljs-keyword\">return<\/span> {\n      <span class=\"hljs-attr\">code<\/span>: <span class=\"hljs-string\">'size-too-large'<\/span>,\n      <span class=\"hljs-attr\">message<\/span>: <span class=\"hljs-string\">`File is larger than 2mb`<\/span>,\n    };\n  }\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">null<\/span>;\n}\n    \n<span class=\"hljs-keyword\">const<\/span> onDrop = React.useCallback(<span class=\"hljs-function\">(<span class=\"hljs-params\">acceptedFiles<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-built_in\">console<\/span>.log(acceptedFiles);\n}, &#91;]);\n    \n<span class=\"hljs-keyword\">const<\/span> {\n  fileRejections,\n  getRootProps,\n  getInputProps,\n  isDragActive,\n} = useDropzone({\n  onDrop,\n  <span class=\"hljs-comment\">\/\/ Pass validator to useDropzone<\/span>\n  <span class=\"hljs-attr\">validator<\/span>: fileSizeValidator,\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><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><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_4CA84BEC8104DB0528B5052503E40960C013D2636C1D45C53DFAB16CD81B995E_1645527613646_image.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1344\" height=\"372\"\/><\/p>\n<p>In the code snippet above, we wrote a custom validation function, <code>fileSizeValidator<\/code>, that validates the maximum size of each file upload. We then added it as the validator value in the <code>useDropzone<\/code> hook.<\/p>\n<h2>Preview image<\/h2>\n<p>To preview images, use <code>URL.createObjectURL<\/code> and pass the file object as an argument to it. Before we do that, create a state to store the file object:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> &#91;files, setFiles] = React.useState(&#91;]);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><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 <code>onDrop<\/code> function, use the <code>createObjectURL<\/code> to generate a preview and attach the preview to the file object:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> onDrop = React.useCallback(<span class=\"hljs-function\">(<span class=\"hljs-params\">acceptedFiles<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-built_in\">console<\/span>.log(acceptedFiles);\n  setFiles(\n    acceptedFiles.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">file<\/span>) =&gt;<\/span>\n      <span class=\"hljs-built_in\">Object<\/span>.assign(file, {\n        <span class=\"hljs-attr\">preview<\/span>: URL.createObjectURL(file),\n      })\n    )\n  );\n}, &#91;]);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><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>Finally loop through the files and display a preview using an image tag if they are images:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">{files.map(<span class=\"hljs-function\"><span class=\"hljs-params\">f<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (<span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{f.preview}<\/span> \/&gt;<\/span><\/span>)\n})}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><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<h2>Upload to cloudinary with unsigned upload<\/h2>\n<p>You can upload the files directly from the browser using <a href=\"https:\/\/cloudinary.com\/documentation\/upload_images#unsigned_upload\">Cloudinary Unsigned Upload<\/a>. Add a button to upload whatever you have in the state:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ If files are in the state, upload the first item in the array of files<\/span>\n\n{files.length &gt; <span class=\"hljs-number\">0<\/span> &amp;&amp; (\n  &lt;button\n    onClick={() =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> url =\n      <span class=\"hljs-string\">'https:\/\/api.cloudinary.com\/v1_1\/codebeast\/image\/upload'<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> formData = <span class=\"hljs-keyword\">new<\/span> FormData();\n      <span class=\"hljs-comment\">\/\/ Use the first item to upload<\/span>\n      let file = files&#91;<span class=\"hljs-number\">0<\/span>];\n      formData.append(<span class=\"hljs-string\">'file'<\/span>, file);\n      formData.append(<span class=\"hljs-string\">'upload_preset'<\/span>, <span class=\"hljs-string\">'s9n5tgkf'<\/span>);\n      fetch(url, {\n        method: <span class=\"hljs-string\">'POST'<\/span>,\n        body: formData,\n      })\n        .then((response) =&gt; {\n          <span class=\"hljs-keyword\">return<\/span> response.json();\n        })\n        .then((data) =&gt; {\n          console.log(data);\n        });\n    }}\n  &gt;\n    Upload\n&lt;\/button&gt;\n)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\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_4CA84BEC8104DB0528B5052503E40960C013D2636C1D45C53DFAB16CD81B995E_1645530720328_image.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1290\" height=\"740\"\/><\/p>\n<h2>Conclusion<\/h2>\n<p>Implementing such a fantastic user experience feature in our React application should now be a thing of the past. This tutorial covered almost all critical areas from validations, upload, and error handling. I hope this tutorial is helpful. Don\u2019t forget to check the official documentation of <a href=\"https:\/\/react-dropzone.js.org\/#src\">React Dropzone<\/a> to explore further and add more features to your app. The complete source code for this tutorial is available on <a href=\"https:\/\/codesandbox.io\/s\/heuristic-tesla-ckk9tx?file=\/src\/App.js\">Codesandbox<\/a>.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28331,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,177,246,371],"class_list":["post-28330","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-javascript","tag-react","tag-under-review"],"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>Implement Drag and Drop for Media Upload in React<\/title>\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\/implement-drag-and-drop-for-media-upload-with-react\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Implement Drag and Drop for Media Upload in React\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-04-28T14:40:14+00:00\" \/>\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\/implement-drag-and-drop-for-media-upload-with-react\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Implement Drag and Drop for Media Upload in React\",\"datePublished\":\"2022-04-28T14:40:14+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/\"},\"wordCount\":9,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"Javascript\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/\",\"name\":\"Implement Drag and Drop for Media Upload in React\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA\",\"datePublished\":\"2022-04-28T14:40:14+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA\",\"width\":1422,\"height\":687},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Implement Drag and Drop for Media Upload in 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\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Implement Drag and Drop for Media Upload in React","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\/implement-drag-and-drop-for-media-upload-with-react\/","og_locale":"en_US","og_type":"article","og_title":"Implement Drag and Drop for Media Upload in React","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-04-28T14:40:14+00:00","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/"},"author":{"name":"","@id":""},"headline":"Implement Drag and Drop for Media Upload in React","datePublished":"2022-04-28T14:40:14+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/"},"wordCount":9,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA","keywords":["Guest Post","Image","Javascript","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/","name":"Implement Drag and Drop for Media Upload in React","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA","datePublished":"2022-04-28T14:40:14+00:00","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA","width":1422,"height":687},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/implement-drag-and-drop-for-media-upload-with-react\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Implement Drag and Drop for Media Upload in 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":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681924801\/Web_Assets\/blog\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2\/e59b1635df7179721f22437b8dee8772b951db19-1422x687-1_283312b4f2.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28330","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=28330"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28330\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28331"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28330"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}