Animatable and accessible modals built with react-spring
This release migrates from being an entirely custom modal library with animations to using @reach/dialog
under the hood. This change should mean better accessibility, a bit more thought-out API for the modals, and a whole community behind their implementation.
With this, I had to rewrite the entire package from scratch after writing multiple differing iterations. Here are the differences the new 2.x version has from 1.x versions:
<div id="modal-root"></div>
anymore since @reach/dialog
handles that for us.<ModalPortal>
no longer exists.<ModalBackdrop>
and <BaseModal>
have become one. More info on this below.styles.css
.import 'react-spring-modal/styles.css'
onDismiss
instead of onRequestClose
.<ModalTitle>
and <ModalCloseTarget>
<ModalTitle>
is an h1
with an as
prop to change it to something else. It gives your h1
an id
and assigns that to the modal's aria-labelledby
attribute to improve accessibility.<ModalCloseTarget>
wraps around your elements and makes it so that when you click on one of those elements it will fire onDismiss
. You can put as many elements inside it as you want. It also does not create it's own HTML element, it uses React Fragments (<></>
).CenterModal
and BottomModal
, we now have ExpandModal
. This modal simply let's you animate the clip-path
CSS property to have your element appear as if it was a growing circle. You get to choose where the center of this circle is with the x
and y
props (these are percentages).For a full look at what accepts what properties, you can look at the new README, look at the source code, or pull it up in an editor with the TypeScript service enabled.
<BaseModal>
works nowFirst, let's talk about how it worked before. In the 1.x
versions, you would simply apply the animations to an <animated.div>
, or similar, element via useTransition
and transition.map
. In the 2.x
version, you no longer manually handle the creation or application of your transition. You only provide the values to create the transition. There are two elements that you can apply transitions to, the overlay and the content. You can also apply any other props you want to these elements. The props these elements accept come from @reach/dialog
's DialogOverlay
and DialogContent
— both of these elements have been passed through react-spring
's animated()
as well. You can further configure your transition with the transitionConfig
prop which simply allows you to pass anything else allowed in useTransition
that isn't from
, enter
, or leave
.
import { config } from 'react-spring'
import { BaseModal } from 'react-spring-modal'
<BaseModal
isOpen={/* ... */}
onDismiss={() => /* ... */}
contentTransition={{ // place your 'from', 'enter', and 'leave' transitions for the content here.
from: { transform: 'scale(0)' },
enter: { transform: 'scale(1)' },
leave: { transform: 'scale(0)' }
}}
contentProps={{ className: 'MyModal w-100 h-100' }},
transitionConfig={{ config: config.stiff }}
>
{/* Content goes here */}
</BaseModal>
This release fixes the a11y bug where, when rendering a modal over another modal, the user can still tab through the elements subordinate to other modals.
This release adds in the prop autoFocus
(defaults to true) which, when set to false
, prevents the automatic focusing on the first focusable element in your modal.
Fixes #3
Alongside this, useCenterModalTransition
and useBottomModalTransition
are now correctly exported 👍
Allows a passed in style prop to coexist on <BottomModal>
and <CenterModal>
with transition and exports useBottomModalTransition.