Reflect Rules in Drag-and-Drop
In the previous section, we made the dropdown menu on an issue card show options based on the user’s relationship to the issue and project. There is still a problem in what the user sees:
If you are signed in as someone who does not own a given project, the issue cards still look draggable. The cursor becomes a grab hand when you hover, dnd-kit lets you pick up the card and drag it around, and when you drop it in a different column, the mutation fires and the server rejects it. The card appears to move, then snaps back, and an error toast shows up in the console.
Nothing bad happens to the data. The server refused the change, so the database was not touched. But it is a poor user experience, because the UI offered an action that the user is not allowed to perform. We will fix that in this section by disabling the drag handles for non-owners, and making the cursor reflect that disabled state.
Use dnd-kit’s disabled Option
useDraggable accepts a disabled: boolean option. When true, dnd-kit:
- Stops listening to pointer events on the draggable element
- Sets
aria-disabled="true"on the element so screen readers know it is not interactive - Prevents the drag from starting even if a pointer event somehow leaks through
We already have isProjectOwner computed from the previous section. Extending the disabled option is a one-line change.
Update src/components/issue-card.tsx:
const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
id: issue._id,
disabled: isOverlay || !isProjectOwner,
});
That isOverlay was already there. It prevents dnd-kit from also registering the floating “drag preview” copy of the card as its own draggable. We add the new condition to it with an OR, so the card is also non-draggable when the current user is not the project’s owner.
Make the Cursor Follow the State
A disabled draggable is still styled with cursor-grab, which looks wrong. The cursor icon suggests the card can be picked up, but clicking does nothing. Fix the cursor class so it only applies when dragging is actually enabled:
-
Import
cnutility at the top ofsrc/components/issue-card.tsx:import { cn } from "@/lib/utils"; -
Update the
CardTitleto usecnand conditionally apply the cursor class:<CardTitle className={cn("flex-1 text-sm font-medium leading-snug", { "cursor-grab active:cursor-grabbing": isProjectOwner, })} {...listeners} {...attributes} > {issue.title} </CardTitle>
Now a non-owner who hovers over an issue card sees a plain text cursor and nothing moves, so it is clear that the card cannot be dragged.
Verify
As the owner
Sign in and open a project you own. Hover over an issue card’s title: cursor turns into a grab hand. Click and drag: dnd-kit picks it up, you can drop it in another column, and the card stays there. This is exactly how it worked before.
As an anonymous visitor
Sign out. Hover over the same issue card title: regular text cursor, no grab hint. Try to click and drag: nothing happens — dnd-kit never starts a drag sequence.
Checkpoint: Commit your progress.
git add .
git commit -m "tracker-15: Disable drag-and-drop for non-owners"
git push