Build a Custom React Element to Preview While Dragging in DnD
Get the project source code below, and follow along with the lesson material.
Download Project Source CodeTo set up the project on your local machine, please follow the directions provided in the README.md
file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.
Lesson Transcript
[00:00 - 00:15] Implement the custom dragging preview. If you launch our app and try to drag the items, you will see that our implementation of the dragging preview is not very faithful to Trello. When you drag the cards in Trello, they get slightly rotated. Let's try to achieve this in our app.
[00:16 - 00:27] To implement this feature, we'll have to use the custom drag layer from React D &D. We want a container component to render the preview. It needs to have position fixed and should take up the whole screen size.
[00:28 - 00:48] So let's define it in the styles.ts. Expert new style component, expert const, custom, drag, layer, container. It's going to be a styled div, set height to 100% width to 100%. It's going to take the whole screen size, pointer events.
[00:49 - 01:08] None. It shouldn't listen to mouse events, position, fixed, top, 0, left, 0, and z index 100. So it's going to be on top of all the other elements. Now create a new file, S RC, custom, drag, layer, TSX.
[01:09 - 01:32] Define an expert new component. Expert, const, custom, drag, layer. It's a functional component. We'll need the dragged item. We get it using use app state. We'll need to get the current offset. We'll get it from the React D&D, const current offset equals use drag layer.
[01:33 - 01:56] Here we pass a function that will get this value from the monitor. We're going to return current offset that will get from monitor using get source client offset. Okay, now we have the dragged item representing the information, the data for the item we are dragging and the current offset that will allow us to position the preview element.
[01:57 - 02:17] So we return if we have dragged item and we know the current offset, then we render a custom drag layer container where we render a column. For now it's going to only be a column and later we'll be checking if we're dragging a card or a column and rendering the corresponding element.
[02:18 - 02:36] Column with ID dragged item ID, text dragged item text. And otherwise we're under null. Nothing. The use drag layer hook that we've used here allows us to get the information from the React D&D internal state.
[02:37 - 02:49] To do this we pass a collector function, that's what we did here, that will receive monitor as an argument. We don't need to specify the type of the monitor argument because TypeScript will infer it from the use drag layer type definition.
[02:50 - 02:59] If you look at it, you will see that the collect function has the monitor type defined on it. We also don't have to worry about the current offset type because it is also automatically derived by TypeScript.
[03:00 - 03:26] Now let's prevent the column preview from hiding. Right now if we go to the app and above the columns render the custom drag layer and then launch the app, you will see that if we start dragging the items, they will be both the column preview and the shadow of the column in the list. Let's fix it. To fix this, first modify the drag preview container props.
[03:27 - 03:38] We want to add a new flag here, is preview. It's also an optional flag and the type is also Boolean. Next along with the opacity, we're going to calculate the transform property.
[03:39 - 04:01] Transform, here we get the props and returns depending on the is preview flag props. Is preview either rotate 5 degrees or undefined. We didn't do anything particularly useful for hiding the element but at least we added a slight rotation. We wanted it anyway because we're trying to copy how trello cards look.
[04:02 - 04:14] Another thing that we want to do is to go to is hidden util function and add the is preview flag to its arguments. It's going to be an optional argument of type Boolean.
[04:15 - 04:29] Add it in the beginning of the check if not is preview and drag item and all other conditions. Format the document. Now open the column component. Add an optional flag is preview.
[04:30 - 04:47] To the props, get it in the props here is preview and now pass it to the column container. Is hidden. Here we pass is preview and also pass is preview as a prop directly to column container is preview.
[04:48 - 05:00] Now we can open custom drug layer and pass the is preview flag to the column preview. You also want to go to use item drag and below the use drug hook add another one use effect.
[05:01 - 08:25] Get another value from the use drug it's called preview and in the use effect we'll subscribe to the changes of the preview value preview. Every time that it changes we will set preview to get empty image and also we pass the options object capture dragging state true. This code will hide the default preview image. Now if you launch the app you should see that the column that we are dragging becomes semi transparent that is expected. We've intentionally used 0.3 value instead of 0 just to make it more visible which column are we dragging and the drug item preview for now will appear in the top left corner of the screen. To move the dragged item preview around you want to open the styles.ts and here we'll define a component which will allow us to update the position change the x and y coordinates of the element by having a style component with dynamic style attributes. So instead of generating a new CSS class for each x or y position we'll have them passed as style properties. Let's begin first we'll need to define the drag preview wrapper props. Those will contain the position of our element. Let's define that type drag preview wrapper props. Here we'll have a field position with x number and y number. Now we'll define the component expert const drag preview wrapper. It's going to be a styled div and here we want to change the attributes instead of the class. So we use address we pass in the props drag preview wrapper props. Then we pass in a function that will process our arguments. Inside of this function we'll destructure the arguments we'll get the position we'll get x and y and then we'll return an object containing the style property. This is why I'm wrapping the return value into the round brackets so that instead instead of having a block we'll have a return of an object. Here we define a style field where we'll have transform property with a value generated by a template string translate x px and y px. Then we want to specify the props of the component drag preview wrapper props. They will match with the attributes props and then we specify an empty list of class properties or CSS properties that we want to append through a class because we only want to have attributes in this case transform attached through the style argument. Go to a C custom drug layer wrap the column into drag preview wrapper and pass in the position and we'll use the current offset value here because it already contains the x and y values current offset . Let's launch the app if you try to drag your items you'll see that now we have a correct item preview that we can drag and the only thing left is to hide the dragged item completely. Previously we used 0.3 opacity on it.
[08:26 - 08:38] Open the styles.ts and update the drag preview container styles. Instead of 0.3 we'll use 0.0. Launch the app and now you should be able to drag the items and it should look correctly.
This lesson preview is part of the Fullstack React with TypeScript Masterclass course and can be unlocked immediately with a \newline Pro subscription or a single-time purchase. Already have access to this course? Log in here.
Get unlimited access to Fullstack React with TypeScript Masterclass, plus 70+ \newline books, guides and courses with the \newline Pro subscription.
![Thumbnail for the \newline course Fullstack React with TypeScript Masterclass](/_next/image?url=https%3A%2F%2Fs3.amazonaws.com%2Fassets.fullstack.io%2Fn%2F20220425171607321_CoverImage_FSReactWTypeScript_Masterclas.png&w=3840&q=75)