Skip to content

A Whole New World

Latest
Compare
Choose a tag to compare
@andria-dev andria-dev released this 21 Mar 00:11

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:

  • You don't need <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.
  • All CSS is grouped together in one file called styles.css.
import 'react-spring-modal/styles.css'
  • The prop to close the modal is now called onDismiss instead of onRequestClose.
  • Added two helper components: <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 (<></>).
  • Alongside 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.

How <BaseModal> works now

First, 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>