As a frontend developer I prefer to work with small companies. That usually means that they don't have a dedicated designer, and developers decide how things should look like themselves. But developers usually are not aware of the best practices when it comes to UI/UX area.
It's tempting to solve any design issue by using modal windows. Especially when we have to deal with forms. After all, a lot of pain points are solved, e.g.
- You can display them anywhere in your application
- Since they are centered you don't need to think about how to place forms so that they look nice. For example, should we center them or place them on the left side?
- It is easier to use one-column layout (which is a recommended approach)
However, sooner or later you may encounter a lot of problems. And one of the best solutions is to simple abandon using modals and use a separate page instead.
Currently I'm working on a project where we use modals extensively. In this article I want to demonstrate what problems do we have and, hopefully, how they can be solved without using modals.
There is a typical situation when you have a list of entities (usually represented as a table), and you need to work with some of them e.g. by filling out a form.
In the picture below I demonstrated a mockup of a table with a list of records. The blue rectangles are action buttons.
The task is: when you click the action button, show a form and ask users to fill it.
One of the first ideas that come to our mind is to show a modal window when the user clicks the action button. And put the form inside the modal.
After all it will be centered and will look nice, right?
While it is true, there are many shortcomings that you might not realize in advance.
Resetting modal state
Imagine the user filled out some of the fields and then accidentally closed the modal by clicking on the black overlay. Will they lose their data?
On the one hand we might save the data that they have just inputted. But what if the user selects another row? We should display data related to the row selected. Thus, it won't work.
Now your boss makes a suggestion: let's disable closing the modal window if the user clicks on the overlay? Well... might sound a little bit weird, since it's a common behaviour (check out consistency and standards heuristic). But okay, it might sound like an option.
Now, you realize that you forgot that the modal can be closed by pushing the
Esc button. So you disable this behaviour as well.
But you cannot simply disable any way of closing the modal, right? Otherwise, how would users hide it? You will still have a close button and users will run into the same issue: they will lose the data.
Now your boss makes another suggestion: how about notifying them that "hey, you haven't submitted the form, are you sure you want to close the window?". Well... you realize that you need to implement this as well by checking if the data is dirty.
Alright, but may I ask you a question?
What's the difference between a dedicated page that has a link "return back to the table", and a modal that you cannot close by clicking on the overlay. And the only way to close it is by clicking the close button/icon which in fact returns you back to the table as well?
I mean, literally, the only difference is that you can see a part of the table behind the modal, but it's covered with the overlay, so it won't help you that much.
One may argue that when you close the modal, you will stay on the same table row (the same Y-scroll position) and you can keep on working with the table.
However, does it often happen that you need to work with sibling rows in the same table? If so, it an indicator that you probably need the bulk action functionality.
But if you indeed need this, then the form inside modal will likely to be a simple one, which might be okay. Otherwise, off the top of my head, I couldn't think of an example of the need to fill complex forms for each table row that are close to each other.
For example, in a CRM you need to change the information about a client. How likely it's going to happen that you need to change the info of 10 clients in a row that are close to each other and you need to change something more complex that a simple flag or something like that?
Another issue is that the form might take a lot of space. Maybe not exactly that large, but since the modal window is centered and is supposed to be relatively small, it's a common case when the form doesn't fit the modal.
Now, in some browsers and OS the scroll is not not visible until you hover the modal or even until you don't try to scroll its content.
So users might wonder, where is the submit button after all?
Now your boss suggest to make the modal bigger. Well, it may help but only partly. We still have mobile devices, we still might not satisfy every possible resolution and use case.
The modal more and more resembles a separate page: it's big, it cannot be easily closed.
Refreshing the page and sharing the modal window link
So, you met all the requirements, and now your boss wonders: how to share a link to the modal? Because in your application users work in teams, and sometimes one user needs to send a link to another user with this form. Ah, also, what happens if users accidentally refresh the page?
Now you realize that you need to support a "route" on the client side, so that the modal can be shared. What's interesting though is that since you don't have a dedicated entity page, you can show the modal only on the page that contains entity list.
So in order to share an entity, you need to share a link that looks like /entities-table/#some_id. And in any case the entity list would be loaded. Which might be okay, but what if the entity doesn't belong to this list anymore?
For example, you have "softly" deleted the entity (e.g. by moving it to an archive) and it cannot be seen in the list? So we have a modal, showing the entity info, but if we close it we will not be able to open it again, right?
Another UX case. You have a large list of entities and you load one of the entities in the end of list (/entities/#very_big_id). And then you shared the link. It's unlikely that you want to load the whole list when your colleague opens the link. So basically, the entity will not be seen (since it's not yet loaded), but the modal will be there. Same issue.
How to solve this?
The solution is easy: don't use modal windows. At least when you need to put something complex inside them.
The only objection I can think of is that you can immediately return back to the list after you close the modal. Well... you have "return back" button in the browser, don't you?
Again, one may argue: my users need to do a lot of actions with the table, with each row, and it's not convenient to return back all the time!
But, it's a quite rare case when users need to handle each row sequentially. If that's the case, then you might make even consider inline editing right inside the table.
Another option would be to use mass edit (bulk) actions.
However, it's much more likely that users need to edit rows in random order. For example, if you have a CRM system, users might need to find customers by email or name and then update them. But it will not happen in alphabetic order, it'll be a pretty random process.
But... what about nice-looking centered design?
Well... two things.
- Who said that you cannot center content inside the page?
- Who said that it's 100% necessary to center a form?
I'm not saying that modals have poor UX in any user interface & we should absolutely abandon using them. Each case is unique. However, you should be aware of possible pros and cons of every solution that you use.
Here is some additional reading related to this topic: https://www.nngroup.com/articles/modal-nonmodal-dialog/