Beautiful and accessible drag and drop for lists with React
key
sWhen rendering items in a list React
recommends using a key
to keep track of the item between re-rendering (docs, guide). In 10.x
we covered over some issues when incorrectly using key
s. 11.x
did not mask incorrect key
usage. In this release we have:
key
skey
usagekey
with react-beautiful-dnd
Closes #1274 #1278 #917
useLayoutEffect
(#1281)eslint-plugin-react-hooks
with useMemoOne
#1264This release is mostly internal changes and our public API remains relatively untouched
The original plan was to move to a totally hooks based api #871. However, we hit a snag: right now it is not possible for a hook
to set up context
. A Droppable
component sets up context
for a Draggable
to consume. So for now we are sticking with our render prop API. Internally we have moved almost everything over to function components and hooks. (Our error boundary still needs to be a class
because function components cannot currently be an error boundary)
Our internal refactor has also resulted in react-beautiful-dnd
now being <StrictMode>
compliant
I have given a talk at React Sydney about my journey converting react-beautiful-dnd
from class
components over to function
components and hooks.
π¬ Deep sea fishing with React hooks
React
peer dependency ^16.3.1
β ^16.8.5
In case you wanted to know why we picked
^16.8.5
π΅οΈββοΈ
^16.8.0
#871React
context
. We could have moved to the new context api in our previous ^16.3.1
dependency, but consuming context
through useContext
in 16.8
has made it a lot easier to shift over.^16.8.4
to use react-redux@7
. We proposed to get this lowed to ^16.8.0
but the project was not keen. We could still claim our React
peer dependency is ^16.8.0
, but that could lead to issues with bundlers if using a version >= 16.8.0
and < 16.8.4
. It would at least be a warning, and might even be worse.^16.8.4
(for react-redux@7
) we went to ^16.8.5
as it contained fixes for shallow rendering which could impact some peoples react-beautiful-dnd
tests<Draggable />
β shouldRespectForceTouch
shouldRespectForceTouch => shouldRespectForcePress
- shouldRespectForceTouch
+ shouldRespectForcePress
Moving to shouldRespectForcePress
is a clearer name given that force press actions can be fired from mouse inputs too.
We will be calling event.preventDefault()
on the following events from a drag handle if shouldRespectForcePress
is set to true
(the new default)
webkitmouseforcechanged
(mouse)touchforcechange
(touch)For the next little while we log a development warning if you are using the old
shouldRespectForceTouch
prop
See #1160. Opting for a better dragging experience out of the box
- shouldRespectForcePress: true,
+ shouldRespectForcePress: false,
useMemoOne
One byproduct of our move to use hooks was the creation of a new package!
useMemoOne
:useMemo
anduseCallback
with a stable cache (semantic guarantee)
useMemo
and useCallback
cache the most recent result. However, this cache can be destroyed by React
when it wants to:
You may rely on useMemo as a performance optimization, not as a semantic guarantee. In the future, React may choose to βforgetβ some previously memoized values and recalculate them on next render, e.g. to free memory for offscreen components. Write your code so that it still works without useMemo β and then add it to optimize performance. - React docs
useMemoOne
and useCallbackOne
are concurrent mode
safe alternatives to useMemo
and useCallback
that do provide semantic guarantee. What this means is that you will always get the same reference for a memoized value so long as there is no input change.
flow
0.96
π€SVGElement
in some testing environment #1249. Thanks @hawkeng for raising thisWe would love your input on our future direction!
react-redux@7
which made this release possible11.0
11.0
beta
DraggableStateSnapshot
and DroppableStateSnapshot
are now correctly populated when dropping outside of a Droppable
. In 10.1
they where being populated with the home location rather than no location. #1178. Thanks @zmi-jlblatt for finding this oneshouldRespectForceTouch
preference for force press touch events that are triggered by some mouse inputs #1192. More information: #1193ISSUE_TEMPLATE.md
#1202. Thanks @lukyth!devDependencies
#1195flow
0.95.1
We will soon be publishing 11.0
. This will have two minor breaking changes:
React
peer dependency from ^16.3.1
to ^16.8.0
shouldRespectForceTouch
name change and default swapMore details: #1194
π§πΆ Release notes designed to be listed to with: "Once there were dragons" @ 4:05
This release pushes react-beautiful-dnd
to new summits of interaction design.
We have removed instant movement (snapping) when moving between lists. Snapping breaks the visual language of moving physical objects around that react-beautiful-dnd
is trying to emulate.
β No snapping when moving between lists
β This is what it used to be (snapping in the π home list after a drop)
You do not need to do anything to get the new animation pattern. I have marked this change as a feature release as it is new design behaviour.
There was a huge amount of work to remove snapping when moving between lists. Who would have thought? Not me π₯΅. I wrote a blog which goes over the journey of this feature in depth. Personally, I think it well worth your time!
πBlog β Beautiful interactions: Crafting elegant and robust drag and drop animations
We have moved to a logo that encapsulates the playfulness and delight that we are striving for with react-beautiful-dnd
Maryanne Nguyen, a very talented designer at Atlassian, has detailed her creative process in creating the new react-beautiful-dnd
logo in a blog π¨
πBlog β maryannemade: react-beautiful-dnd
logo
react-beautiful-dnd
tries to respect standard browser interactions as much as possible. Currently, the library plays well with force touch interactions:
If the user force presses on the element before they have moved the element (even if a drag has already started) then the drag is cancelled and the standard force press action occurs. For an anchor, this is a website preview.
Unfortunately, heavy presses can cancel a drag. It can be tricky at times to get the right amount of pressure to correctly use touch dragging. This can be frustrating for users.
We have added an option for you to opt-out of respecting force touch interactions. This option will disable force press interactions on the drag handle. However, it allows for a more consistent touch dragging interaction.
We have added shouldRespectForceTouch
as a prop to <Draggable />
. It defaults to true
in order to respect force touch interactions, but you can set it to false
to opt out of respecting force touch
<Draggable
draggableId="draggable"
+ shouldRespectForceTouch={false}
>
</Draggable>
This change resulted in a feature release. The default behaviour matches the behaviour of previous versions.
Right now shouldRespectForceTouch
defaults to true
in order to respect browser interactions. However, for this specific use case, I am thinking that the default could be to not respect force touch in order to have a more consistent touch dragging experience out of the box.
I have created a request for discussion to collect other people's thoughts on what the default should be.
We have added a new value to the DroppableStateSnapshot
: draggingFromThisWith
type DroppableStateSnapshot = {|
isDraggingOver: boolean,
draggingOverWith: ?DraggableId,
+ draggingFromThisWith: ?DraggableId,
|};
draggingFromThisWith
is populated with the draggableId
of the dragging item in the π home list for the entire drag. This allows you to style the home list differently from the other lists if you like. We recommend you do this to make it clear which list the user is dragging from. You can read more about the thinking behind this in my blog
In this example we set the background-color
of the home list to pink
when we are dragging over the list. We set the background-color
of the home list to blue
when not dragging over the home list.
We have totally overhauled our documentation to be easier to find and use information.
Our README.md
was getting too big. It was hard for new comers to know where to start, and it was hard for consumers of the library to quickly find information. We have simplified our README.md
and added a comprehensive documentation section which links off to categories of information.
The README.md
now contains a high-level introduction to the project, feature set, how to get started and then links to the rest of the documentation.
Information in the README.md
:
gif
showing off what the library is aboutAbout
section which links off information useful to understand, evaluate and get started with the library.API
was under a wall of design thinking information which would not be useful to a non-evaluatorA big thank you to @Noviny for his incredible efforts in helping to create this new information architecture
We have made our examples brighter and more colourful
Previous | New style |
---|---|
We have also upgraded to Storybook v5
and added our new logo to the header
redux
devtools when process.env.NODE_ENV === 'development'
#1085. Thanks @teleaziz!!transition
for a property other than transform
that finished during a drop animation on a Draggable
could cause the drop to end suddenly #1096position:fixed
lists on ie11 #1091 #1088. Thanks @InvisibleBacon for raising this oneflow
0.94
#1119emotion
π©βπ€ #1128cypress.io
. Also added a few more browser tests #1122I have been off for a month and I had a great time. I could go for another month...
Here is what we plan on working on next: Up next milestone
Also, a reminder that we have two planned breaking changes coming up:
React
peer dependency of 16.6+ #984flow
to TypeScript
#982. This might not be a breaking change if we have a good flow
story π€Unplanned but possible:
doctype
warning π¨ββοΈ #1068We have added a dev only warning to notify you if the pages doctype
is supported #1068 #1040. We only support the html5 doctype
(<!doctype html>
). The doctype
impacts a number of measurement calculations. Previously if you used another doctype
things might work, but there could be some strange issues depending on your css configuration (eg if you did not have body height: 100%
). Rather than trying to account for every strange doctype
out there - we print a dev warning to the console
! π We also now call this out in the docs.
My hope is that this change makes it easier to fall into the pit of success
Just a public service announcement: if you do not add a doctype
tag, browsers will use some other doctype
such as "Quirks mode". Please add a doctype
to your pages!
<!doctype html>
react-frame-component
#796. Thanks @jdillick for the ideasflow
0.91
#1065Previously when a user picked up a draggable item that was near the edge of a scrollable area it could trigger a large and jarring auto scroll. We have created a solution that gets around this problem in a really elegant way.
I have created a video which goes over what we did in a bit of detail πΊ
A big thank you to @ajaymathur and @jjcm for their huge help with this one
ISSUE_TEMPLATE.md
draggableId
and droppableId
) successfully in react-beautiful-dnd
README.md
link #970. Thanks @fzembow!!Draggable > type
#952. Thanks @DmitryGonchar!!Droppable
s #966. Thanks @woohling!Draggable
and Droppable
boolean props #945.π Remember:
null
is not a validboolean
prop type. Either pass intrue
,false
orundefined
to get the ReactdefaultProp
value.
README.md
#943flow
crashing. Thanks @TrySound for your help with this one! #1008 #1007flow
0.88
4x
#989emotion
to my first love: styled-components
4x
for examples.We have two planned breaking changes coming up in early 2019:
flow
to TypeScript
#982My hope is to batch these two breaking changes into a single breaking change release
<body>
element. Fixes compatability issue with Semantic UI #904. We also wrote a new guide: how we detect scroll containers. Thanks @MohammedAl-Mahdawi for raising this and @seancurtis for helping me work through it.Array.prototype.find
message from docs #933. Thanks @wuweiweiwu!styled-components
4.0
api change to docs #926. Thanks @balonsom!!README.md
#943flow
types #910. Previously they were being lost in a HOC. Huge thank you to @TrySound for this one! He also added a flow
test to ensure there is no regressions on this ππ§πΆ Release notes designed to be listed to with Angus & Julia Stone - Chateau (ARTY Remix)
π 30% faster π₯ smarter collision engine πΉ more robust keyboard movement system π³ new: combine items π£ new: add and remove items during a drag π² new: tree library @atlaskit/tree by @Confluence
I know right!? Pretty awesome!! Okay, lets get into the details
9.x
β 10.x
This release is a listed as a breaking change π₯. However, the risk of actual breakage is very low. Most consumers should be able to upgrade without any issues π. We will call out any breaking changes in these releases notes.
Draggable
s #511react-beautiful-dnd
now supports the combining of Draggable
s π€©
We have created a combining guide which will show you how you can use the new feature and the thinking behind it.
I am biased, but the combining guide is really worth a read! The logic for doing combining in conjunction with reordering is very cool
Draggable
s while dragging #484react-beautiful-dnd
now supports the adding and removing of Draggable
s during a drag. This is a powerful feature that unlocks a lot of behaviors
Lazy loading | Trees! (Read more below) |
---|---|
We have created a guide to help you use this new feature.
@atlaskit/tree
π²πIn conjunction with this release, we have also released a new tree library: @atlaskit/tree
!!! π
It is a beautiful and accessible tree implementation built on top of react-beautiful-dnd
Hover to expand | Drop onto expanded parent | Drop onto collapsed parent | Drop on another item to create new group |
---|---|---|---|
We have significantly improved the performance of react-beautiful-dnd
.
You can read about how we did this in our blog "Grabbing the flame π₯"
Our collision engine has been rebuilt in order to take into account:
This results in a much more consistent and natural movement experience.
There was a flaw in the previous engine where edge detection did not consider what was already displaced.
The collision engine is now aware of displacement and so will now always shift items when the visible center goes over the visible edge of an item - even if the visible edge is displaced.
The collision engine is also now aware of the direction a user is currently moving in which is used to facilitate our new combining mode.
The internal keyboard movement system has been completely rebuilt to provide more spacing flexibility and resilience. Improvements:
margin
safely on any edge of a Draggable
(as long as it does not lead to margin collapsing between items) #201Example of old spacing issue | Now handled correctly |
---|---|
We have moved to using only CSS
for the drop animation for performance reasons (you can read more about that in "Grabbing the flame π₯").
As a side benefit of this you are now able to tweak the drop animation, or opt out of it completely. We recommend not opting out the drop animation as it is important communication for the user.
Your own animation | No animation (not recommended) |
---|---|
We have created a drop animation guide to assist you
We have made our development build warnings and error message prettier and more informative
We only long warnings if there are actual setup issues (not just for fun!). That said, if you want to, you are now able to disable all warnings:
// disable all development only warnings
window['__react-beautiful-dnd-disable-dev-warnings'] = true;
We have also added tests to ensure that these messages are correctly dropped from production builds.
Previously we required consumers to polyfill Array.prototype.find
in order for react-beautiful-dnd
to work in ie11. We now bake in our own light ponyfills so that you are not required to polyfill anything to use react-beautiful-dnd
in ie11
react-beautiful-dnd
10.0.0
is actually a little bit smaller than 9.x
. Which is amazing considering how many new capabilities the library has!
Hooks
Responders
DragDropContext > Responders
DragDropContext > Responders
Recently React
announced a new alpha Hooks API
. To avoid overloading the term Hook
and confusing people, we have replaced our usage of the word Hook
to Responder
. The names of the actual Hooks
Responders
are unchanged:
onBeforeDragStart
onDragStart
onDragUpdate
onDragEnd
This is a type
name change, as well as changing how we refer to them in the docs.
-type HookProvided = {|
+type ResponderProvided = {|
announce: Announce,
|};
-type OnBeforeDragStartHook = (start: DragStart) => mixed;
+type OnBeforeDragStartResponder = (start: DragStart) => mixed;
-type OnDragStartHook = (
+type OnDragStartResponder = (
start: DragStart,
provided: ResponderProvided,
) => mixed;
-type OnDragUpdateHook = (
+type OnDragUpdateResponder = (
update: DragUpdate,
provided: ResponderProvided,
) => mixed;
-type OnDragEndHook = (
+type OnDragEndResponder = (
result: DropResult,
provided: ResponderProvided,
) => mixed;
-type Hooks = {|
- onBeforeDragStart?: OnBeforeDragStartHook,
- onDragStart?: OnDragStartHook,
- onDragUpdate?: OnDragUpdateHook,
- // always required
- onDragEnd: OnDragEndHook,
-|};
+type Responders = {|
+ onBeforeDragStart?: OnBeforeDragStartResponder,
+ onDragStart?: OnDragStartResponder,
+ onDragUpdate?: OnDragUpdateResponder,
+ // always required
+ onDragEnd: OnDragEndResponder,
+|};
This is a breaking change π₯. But it should be a fairly trivial
type
rename if you are usingflow
orTypeScript
. This would only impact you if you are directly importing the types:
- // this would now break:
-import type { OnDragStartHook } from 'react-beautiful-dnd`
+// need to use the new type name:
+import type { OnDragStartResponder } from 'react-beautiful-dnd`
Responder
timingsIn order to improve consistency we now force onDragStart
and onDragUpdate
to be in the tick
after the snapshot
values are updated. Previously there were in the same tick
. We do this to ensure there is a full React
render before calling the hooks. This was generally the case anyway so consumers should not be impacted. I found some very edge case scenarios where onDragStart
could be batched into the same render
pass by React
as a snapshot
update.
You can read all the timing details in our Responder guide.
This could be classified as a breaking change π₯, although the risk of breakage is almost nothing. In fact, it fixed a bug we found in one case π€·β
Responder
s π΅οΈββοΈThe values provided to the Responders
now has some new information!
DragStart
now contains mode
DragStart
is supplied toonDragStart
type DragStart = {|
draggableId: DraggableId,
type: TypeId,
source: DraggableLocation,
+ mode: MovementMode,
|};
+ type MovementMode = 'FLUID' | 'SNAP';
There are two seperate modes that a drag can be in
'FLUID'
: everything is done in response to highly granular input (eg mouse)'SNAP'
: items move in response to commands (eg keyboard)
SNAP
may also include our new programmatic dragging mode we have planned #162
DragUpdate
(and DragResult
) now contain combine
DragUpdate
is supplied toonDragUpdate
DropResult
is supplied toonDragEnd
In order to facilitate the new combining mode a DragUpdate
and DragResult
now contain combine
information
type DragUpdate = {|
...DragStart,
// may not have any destination (drag to nowhere)
destination: ?DraggableLocation,
+ // populated when a draggable is dragging over another in combine mode
+ combine: ?Combine,
|};
+ // details of the item that is being combined with
+ type Combine = {|
+ draggableId: DraggableId,
+ droppableId: DroppableId,
+ |};
// DropResult gets these too it it extends DragUpdate
type DropResult = {|
...DragUpdate,
reason: DropReason,
|};
Draggable
π¨βπ¨We now provide your Draggable
with more information for you to use!
type DraggableStateSnapshot = {|
isDragging: boolean,
isDropAnimating: boolean,
draggingOver: ?DroppableId,
+ // Information about a drop animation
+ dropAnimation: ?DropAnimation
+ // the id of a draggable that you are combining with
+ combineWith: ?DraggableId,
+ // a combine target is being dragged over by
+ combineTargetFor: ?DraggableId,
+ // What type of movement is being done: 'FLUID' or 'SNAP'
+ mode: ?MovementMode,
|};
+ // information about a drop animation that you can patch if you like
+ type DropAnimation = {|
+ duration: number,
+ curve: string,
+ moveTo: Position,
+ opacity: ?number,
+ scale: ?number,
+ |};
As mentioned previously, we have moved to using a CSS animation for our drop animation. We where able to maintain the exact same visual animation using CSS as we where with a spring
based animation. You can read more about this in "Grabbing the flame π₯".
Breaking change π₯. We previously rendered a
Draggable
at60fps
to get it to its home location. Now we let CSS do it. If you were patching the drop animation then this change will break you. Good news, it will now be much easier for you! Check out our drop animation guide.
Draggable
an index
prop (a common setup error)DragDropContext
is unmounted. It will now print a dev only warning explaining any problems and how you could avoid dropping screen reader messages #556React
peer dependency version. npm
will warn you about this, but we are getting a lot of issues about this. So we decided to bake our own warning into the libraryposition:fixed
containerindex
es need to be dense and start from 0
#892ReactDOM.createPortal
could cause the drag to lockconsole.*
statements are removed in production buildsstylelint
flow
0.86
#851We have a new Community section and Addons section in our docs. If you have something that you would like to submit please pull request.
Thanks to these people who have already added content:
We have a few request for discussion (RFD) issues that would benefit from more input:
This release has been months of hard work in the making. Thank you to everybody who has contributed to, and supported this release. A special thanks to: