These guidelines provide an opinionated way to implement drag and drop experiences with Pragmatic drag and drop for Atlassian interfaces. These guidelines work within web platform design constraints for drag and drop, and aim to optimise clarity and performance. Non-Atlassian consumers are welcome to use these guidelines, or create their own visual language for drag and drop. The core package does not have any baked in design opinions, but some of the optional packages embody these design choices.
These design decisions are available in our Pragmatic drag drop Figma UI Kit (Atlassian only).
We plan on soon making this Figma public soon.
Cards, lists, and other UI can often be dragged and reordered. Design clear and consistent drag and drop experiences in Atlassian products following these principles:
As a starting position, if an entity is draggable (eg a card), then make the whole entity draggable. If the entity has other interactive parts (eg buttons, dropdowns), then just make the drag handle icon the draggable part of the entity.
Something to keep in mind is that making an entire entity draggable
will prevent text selection
inside that entity (platform limitation)
It should be clear to a user that an entity is draggable by using the following:
- a drag handle icon
- cursor changes
- background color changes
Please also see our accessibility guide which talks about our guidance for placing an action menu trigger on draggable entities.
A drag handle icon helps people understand what is draggable. Use the DragHandlerIcon
from
@atlaskit/icon as your drag handle icon. Please use "color.icon"
as the icon
color as it provides the greatest contrast for accessibility.
import DragHandlerIcon from '@atlaskit/icon/glyph/drag-handler';
import { token } from '@atlaskit/tokens';
function App() {
return <DragHandlerIcon label="Drag list item" primaryColor={token('color.icon')} />;
}
Our
drag handle icon button
uses "color.text"
as the icon color (rather than "color.icon"
) to align with other icon buttons
in our system, and for correct colors for different states. We expect this minor mismatch will be
corrected during our upcoming icon work.
When dragging is a primary action of an entity, there should be a visible drag handle on the left hand side of the entity at all times.
If dragging is possible on the item, but dragging is not considered a primary action (it is a
"delighter"), then you can just show the drag handle icon on focus
and hover
.
:hover
and :focus-within
When the drag handle is a delighter, it can drop down to a minium of 16px
in width. Try to keep
the whole entity draggable so that the draggable touch target is greater than 24px x 24px
. 16px
is the size of a "small"
@atlaskit/icon.
16px
) visible on :hover
and :focus-within
When the drag handle is the only part of an entity that is draggable, it's touch target size should
be at least 24px x 24px
in size (which is the size of a @atlaskit/icon). You
will see that the spacing of our example item has changed to give the drag handle more breathing
room.
Some entities are considered to be "implied" to be draggable (eg cards, columns, tree items) and these entities do not require a drag handle icon - although you can still add them. Implied draggable entities should use background color and cursor changes to make it clear which part of the entity is draggable, and there should be a strong preference to make as much of the entity draggable as possible.
Sometimes, your drag handle icon should be a button for triggering actions too (see our accessibility guide). In those cases, please use our drag handle icon button.
Use cursor:grab
as a signal that an entity is draggable. Only the draggable part of an entity
should have cursor:grab
. So when a draggable is only draggable from a drag handle, only the drag
handle should have cursor:grab
.
:hover
and :focus-within
16px
) visible on :hover
and :focus-within
When dragging is a secondary action, and the entity has multiple operations, it might be
appropriate to delay the cursor:grab
by 800ms
.
cursor:drag
delayed by 800ms
You can implement this behaviour just using CSS (no JS needed!)
.item:hover {
animation-duration: 0s;
animation-name: change-cursor;
animation-delay: 800ms;
animation-fill-mode: forwards;
}
@keyframes change-cursor {
to {
cursor: grab;
}
}
The draggable part of an entity should have a background color change applied when hovering over it.
Please use the appropriate hover token for the entity.
Usually for a draggable entity you will be using:
elevation.surface
as the background color.elevation.surface.hovered
on as thehover
background color on the draggable part of the entity.
:hover
and :focus-within
16px
) visible on :hover
and :focus-within
For some situations it might be appriopriate to use a different color pairing. Please try to use a
".background"
color token for the draggable entity, and a matching ".hovered"
token for the
hover.
While an item is being dragged, it is important that you give clear feedback to the user about what is being dragged, and what will occur when the user completes the drag.
A drag preview is a representation of the item being dragged. Generally a drag preview is a picture of the item being dragged around the page, and not the draggable item itself.
When an item is small and simple, the drag preview can be an exact copy of the item being dragged. If an item is larger or more complex, you should simplify the drag preview.
Simplification suggestions:
- Use a maximum of three pieces of information in a preview
- Use a maximum preview size of
280px x 280px
to prevent super low drag preview opacity on Windows
Standard
Drag previews should generally be pushed away from the users pointer by space.100
vertically, and
space.200
horizontally. Do not rotate the drag preview.
{
x: token('space.200', '16px'),
y: token('space.100', '8px'),
}
Cards
Cards are to be dragged from the point they're grabbed from (no offset).
Do not rotate card drag previews. Exception: Trello, which has a 4deg
rotation.
Due to
web platform constraints, we
have limited control of the cursor during a drag operation. The cursor will generally be
cursor:default
during a drag operation.
More information about cursors.
While an item is being dragged, the original item should stay in place and dim to 40%
opacity
(opacity: 0.4
) while the drag preview is being moved around.
For multi-item drag previews, use a stacked appearance with a badge indicating the number of items being dragged.
- Four or more small items such as list items should appear as a stacked preview under the first item. Less than four small items can appear separately where space allows (all items showing in the preview).
- Any more than one large item (card) should show as a stack with a badge indicating the number underneath.
Implement with native drag previews, or use the Figma kit (Atlassian only) in designs.
It is important to communicate during a drag operation, what the result of the operation will be. There are two signals you can use to indicate drop placement:
- Drop indicator (a line)
- Background color (
color.background.selected.hovered
)
Drop indicator
The drop indicator line is used to communicate relative placement (for example, before or after an item in a list)
A drop indicator line should have the following properties:
Property | Value |
---|---|
Stroke size | 2px |
Color | "color.border.selected" |
Terminal diameter | 8px ("space.100" ) |
Border radius on right hand side | none |
The terminal should bleed 4px
outwards on the left hand side of the target item. When this
bleeding is not possible due to UI constraints (such as the element appearing in a scroll container
which would cause the terminal to be cut off) then the terminal "bleeding" can be disabled and the
terminal can sit against the left edge of the entity
For stacked items, the line should appear in the middle of the gap between the items.
- Edge detection package: determines when and where the drop indicator shows based on the location of the dragged item.
- React drop indicator package: draw drop indicators
A drop indicator line should not be used when a draggable item is being dragged over a droppable area where there is no relative placement possible (for example, dropping into an empty sibling list).
Background color
A background color change is used to communicate that an item will be placed within a particular droppable area. Background color changes should be used when there are multiple possible areas of the page a draggable item can be dropped on. The droppable area that the user is currently over should have its background color changed. A background color change should also occur when a draggable item starts in a droppable area, when there are multiple possible droppable areas.
A background color change to communicate that dropping is possible should only be applied when a user can perform a drop operation. Sometimes an entity (eg a column) only allows dropping on a subset of that entity. Only the subset that allows dropping should have a background color change, and only when the user is dragging over that subset. We don't want to have a situation where a background color changes, but when the user drops, nothing happens.
Background color change animation details:
Property | Value |
---|---|
Background color | "color.background.selected.hovered" |
Easing | cubic-bezier(0.15, 1.0, 0.3, 1.0) (import {easeInOut} from '@atlaskit/motion' ) |
Duration | 350ms (import {mediumDurationMs} from '@atlaskit/motion' ) |
When draggable items can only be moved relatively within a single container, then no background color change should be used when the user is dragging something within the experience.
After a drop, the drag preview disappears and the original item should to it's new location. To improve clarity about what the user achieved, the background color of the moved item should flash once it has been moved.
.
We have implemented this flash in our flourish package for you to use with any framework.
Background color flash details:
Property | Value |
---|---|
Background color | "color.background.selected" |
Easing | cubic-bezier(0.25, 0.1, 0.25, 1.0) (not available in @atlaskit/motion ) |
Duration | 700ms (import {largeDurationMs} from '@atlaskit/motion' ) |
Be sure to see our accessibility guidelines
All draggable items should also have the ability to trigger the same outcomes using assistive technology friendly controls.
Please make drag handle icons visible (where possible) as this is a helpful signal for people that an item is draggable.
If the item already has a more actions (…) menu, put the move actions inside of the menu. This provides a keyboard accessible way to move items that doesn’t rely on mouse clicking and dragging.
If the entity does not have any more actions (…), make the drag handle icon into a menu button. When triggered, the drag handle button opens a menu that allows the users to move the item.
Use the drag handle menu component in code or the Figma kit drag handle menu (Atlassian only) in designs.
How to show when more than one element is selected to be dragged.
Use color.background.selected
and color.border.selected
to show the elements that have been
selected, then change to the typical background color at 40% opacity once dragging begins. This
shows where the objects are currently, and where they'll return if no drag location is chosen.
Because cards are larger, multiple cards should be stacked under the first card in the preview. Use a badge to show how many items are being moved.
Checkboxes are highly recommended to show when one or more items are selected.
Use the selected background color token to indicate which items have been selected. Use drag previews as usual, with all items being dragged in a column in the order they’d appear when dropped.
For more than three or four items, show a badge indicating the number and an implied stack beneath the top item.