Journal
Nested modal drawers with parallax
Recently, I realized that I never wired up the project form’s “New client…” option to the client form in Cushion’s timeline beta, so if a user tried to create a new client inline, nothing would happen—how embarrassing! I must’ve held off on this because it would require an upgrade to my modal drawer system to handle “nested” drawers. This means that a user could open another drawer while a drawer is already open, which would require the parent drawer to shift and lose focus until the child drawer is closed. This seemed like a healthy amount of work, so I held off for a while—until this past weekend.
I knew I absolutely needed the ability to create a client when creating a project, so I had to power through any procrastination that was holding me back. I sat down and planned it out. In that moment, I realized that this actually wouldn’t be too much work. If I kept the system incredibly simple (by assuming for the moment that I’ll only have one nested drawer at a given time), I could greatly reduce the work because I don’t need to keep track of a recursive state (in case a nested drawer has a nested drawer, etc.). With that in mind, I relied on a single prop for Cushion’s modals, called depth
.
The depth
property is zero by default, but increases on the parent drawer if a nested drawer is opened. When the depth is greater than zero, the parent drawer shifts to an x-coordinate that is the depth multiplied by a distance. At the same time, the parent drawer loses focuses and only accepts the escape hotkey if the depth
property is zero again. This lets the top-most drawer handle the escape hotkey and any focus events. The background of the top-most drawer intercepts any click events, so the top-most drawer is the only one that’s closed when clicking the background. This system actually worked perfectly well for my immediate need, and I can anticipate an upgrade path where opening a nested drawer several levels deep could simply propagate up and increase all the parents’ depth
properties. At the same time, that scenario might actually be a good “design smell” to pinpoint a UI that’s too complex.
The last part to consider was the transition. The current modal drawer fades in and shifts 72px from the right. I wanted to keep this transition, but I saw an opportunity to improve it when dealing with nested drawers. If we think tangibly, and a nested drawer is sliding on top of a parent drawer, it would shift the parent drawer, but not as much as itself unless they’re 1:1 and glued together. With this in mind, a nice effect could be reducing the travel distance of the parent drawers based on their depth, so the active drawer travels 72px, but the parent drawer travels 64px. Think of turning pages in a book. This would then scale to a future system that might have the multiple nested drawers I’m trying to avoid.
I actually shared a video of this parallax effect on Twitter, and despite feeling like a no-big-deal detail that I simply wanted to share, it got significantly more engagement (barf) than most of my Cushion tweets do. It’s good to know that folks still appreciate the delightful details that I enjoy designing so much.