The Rest
The Container Decision — Modal, Panel, Tab, or Route
Every time a user clicks something in your interface, you make a decision about what happens to their current context. Does it disappear? Does it stay visible? Does it freeze? Does it partially change?
That decision — more than color, more than typography, more than component style — determines whether the user feels oriented or lost, in control or interrupted, fluent or constantly restarting.
There are four containers available to you: a modal, a side panel or drawer, a tab, and a full route change. Each one represents a different answer to the same question: what happens to the user's current context? Each one makes a specific contract with the user about where they are, what's behind them, and what's possible from here.
Choosing between them is not primarily a visual decision. It's a structural one. And the content itself — its richness, its independence, its depth — is usually what makes the right answer clear.
The Context Axis
Before examining each container, it helps to understand the single axis they all sit on: how much of the user's previous context survives.
- Modal — context is suspended. The world behind it is frozen and dimmed. The user must resolve this moment before anything else continues.
- Side panel / drawer / bottom sheet — context is retained and visible. The user hasn't left. The panel is additive — the background remains present and part of the experience.
- Tab — context is partially replaced. The parent stays constant but a content slice changes. The user is still with the same entity, looking at a different facet of it.
- Full route — context is fully replaced. The previous screen is gone. The user is somewhere new, with their own URL, their own history entry, their own identity.
This axis maps directly to the URL contract from the previous article:
| Container | URL change? | |---|---| | Modal | No — you haven't gone anywhere | | Side panel | Sometimes — only if the content is independently shareable | | Tab | Yes — it's a distinct, addressable facet of an entity | | Route | Always — you are somewhere new |
If you find yourself wanting to change the URL for a modal, that's a signal it should be a route. If you find yourself not wanting to change the URL for a route, that's a signal it shouldn't be a route. The URL test is one of the fastest ways to verify whether you've chosen the right container.
The Modal — Suspend Everything
A modal's contract is the most aggressive of the four. It freezes the background, dims it, and places itself between the user and everything else. It is, by design, an interruption. Its implicit message is: stop what you're doing, this requires your attention and resolution before you continue.
That message is only honest when the content genuinely warrants interruption. Modals earn their contract when:
- A decision is required before the system can proceed. Confirmation dialogs, destructive action warnings, permission requests — these genuinely need the user's full attention and a binary response.
- The content is brief and self-contained. A modal works for a short form, a single confirmation, a small amount of information that requires acknowledgment. It is not a container for rich, explorable content.
- Resolution is the only valid next step. The user cannot and should not be able to ignore this and keep working. The interruption is intentional.
Where modals break their contract
The most common violation is using a modal for content that is too rich for its container. A detailed record, a multi-section form, a profile with tabs — these turn the modal into a cramped, scrolling, deeply unsatisfying experience. The user is trying to work inside an interruption, which is a contradiction. Modals aren't residences. They're moments.
The second violation is modal stacking — opening a new modal from inside a modal. Each layer is telling the user they're in an even deeper suspension of their original context. By the second stack, the user has completely lost their sense of where they started. If content naturally branches from a modal, the original container was probably wrong.
The third violation is using a modal to display content the user might want to share, bookmark, or return to. A modal has no URL. It cannot be linked. It cannot be reopened from browser history. Using it for shareable content is invisibly destroying that content's addressability.
The modal's correct role
Modals are for decisions and alerts, not for content and navigation. Deleting a record, confirming a destructive action, requesting a critical permission, displaying a system alert — these are modal moments. Anything else should be examined carefully before reaching for the modal.
The Side Panel, Drawer, and Bottom Sheet — Stay and Explore
The side panel (desktop), drawer (either orientation), and bottom sheet (mobile) share a contract: you are still in your current context, and I am offering you something additional without removing you from it.
The background remains visible and real. The user hasn't navigated. The panel is additive — it layers content on top of the current view rather than replacing it. This makes the panel the right container for a specific kind of interaction: exploring a detail from within the context that contains it.
The panel works when:
- The current view is the primary context. A list of customers, a table of transactions, a grid of products — the list is where the user is working. The panel surfaces detail about one item from that list without abandoning the list.
- The content is a preview or summary, not a full entity. The panel has a ceiling. It's constrained real estate, and it should be. If the content can be reasonably summarized in a sidebar — key details, quick stats, a handful of actions — the panel is appropriate.
- The user's workflow requires staying. Sales reps scanning through records, support agents triaging tickets, managers reviewing a queue — these users need to see detail without losing their place. The panel is the tool for that workflow specifically.
Where panels break their contract
The panel breaks down when the content it's trying to hold is too rich for its container. A full entity with multiple sections, its own sub-navigation, deep activity history, nested relationships — this content doesn't belong in a panel. You've taken a first-class object and squeezed it into a sidebar. The user will spend the entire interaction fighting the constraints of the container rather than engaging with the content.
The other failure is using a panel for content that the user might want to share or return to directly. Like a modal, a panel usually has no URL. If someone says "here's that customer I was telling you about" and the customer only exists as a panel state, the link doesn't exist.
The panel URL question
The panel is the only container where the URL decision has meaningful nuance. In most cases, a panel doesn't change the URL — the user is still on the list page, just with a detail layer open. But in some workflows, the panel state is significant enough to deserve a URL: if a user could reasonably want to share "the customer list with Sarah Chen's panel open," that state deserves a URL parameter.
The test: could someone receive this URL and find it useful? If the answer is yes, encode it. If the answer is "they'd just see the list without the panel, which is fine," leave the URL alone.
The Tab — Same Entity, Different Facet
Tabs are the most misused navigational element in system design, largely because they look like navigation without being navigation. Understanding their contract precisely is the difference between a tab that helps users and a tab that confuses them.
A tab's contract: the parent context is constant, and I am showing you a different slice of it.
The user is still on the same entity — the same customer, the same order, the same project. They haven't moved. They're looking at a different facet of the same thing: overview vs. activity vs. contacts vs. documents. The parent doesn't change. Only the visible slice does.
This means tabs are appropriate when:
- The content belongs to a single parent entity. All tabs are facets of the same record or context. They don't navigate between different entities or different sections of the application.
- All tabs are genuinely peers. They're at the same hierarchical level within their parent. A tab that navigates away from the parent while others don't breaks the sibling contract.
- The parent identity remains constant across all tabs. The user should always know which entity they're looking at, regardless of which tab is active. The tab is changing the view, not the subject.
Tabs deserve URLs
Because tabs represent distinct, addressable facets of an entity, they should almost always have URLs. /customers/sarah-chen/activity is a different destination from /customers/sarah-chen/contacts. Both are valid locations that a user might want to share, bookmark, or return to directly.
A tab without a URL is a view state that can't be referenced, shared, or restored. In most systems this is an unnecessary loss — routing to a specific tab costs very little to implement and returns significant value to users who work inside complex records daily.
When content should be a tab vs. a route change
The clearest test: does this content belong to a parent entity, or is it an entity itself?
A customer's activity history belongs to the customer. It's a tab. A specific activity item — a call, a deal, a support ticket — is its own entity. It's a route.
If clicking something within a tab takes the user to content that has its own identity, its own depth, and its own potential sub-navigation, that content is a route destination, not another tab layer. Tabs within tabs are almost always a sign that the inner content should be a route.
The Full Route — A New Destination
A route change is the clearest contract: you are somewhere new. The previous context is gone, replaced entirely by the new destination. This is the only container that always deserves a URL — because it's the only one that represents a genuine change of location.
A full route is appropriate when:
- The content is a first-class entity with its own identity, its own depth, and its own potential sub-navigation.
- The user might want to share, bookmark, or directly link to this content. A URL is the mechanism for all three.
- The content has enough richness that no other container could hold it without compromising it.
- The user's workflow involves spending real time here. They're not glancing and returning. They're working.
The list-to-detail pattern
The most common route decision in system design is the list-to-detail pattern: a list of entities, each of which routes to a full record page. This pattern is almost always correct for first-class entities — customers, orders, projects, users, tickets. These entities have their own identity and depth. They deserve their own pages.
The objection is usually "but I lose my place in the list." This is a list state problem, not a routing problem. The solution is restoring scroll position and filter state when the user navigates back — a solvable engineering problem. Avoiding routing to preserve list state is trading away the fundamental navigational contract to paper over a state management issue.
Applying All Four — A CRM Example
A CRM customer list is an ideal scenario for examining how all four containers work together — because a real CRM uses all of them, and each earns its place.
Clicking a customer's name routes to the full customer profile. This is the primary interaction. The customer is a first-class entity with their own contacts, deals, activity history, documents, and notes. They deserve their own URL, their own page, their own place in browser history. This is non-negotiable.
Hovering or using a secondary action on a list row opens a side panel with a customer preview: name, key contact info, last activity, one or two quick actions (send email, log a call). This serves users who are scanning the list and need to glance at detail without committing to navigation. The panel is correct here because the list is the primary context and the customer detail is additive. This panel probably doesn't need a URL — the user is scanning, not referencing.
Within the customer profile, tabs separate the facets of the customer entity: Overview, Activity, Deals, Contacts, Documents. Each tab has a URL. A colleague can link to /customers/sarah-chen/deals directly. The customer is the parent; the tabs are facets.
Deleting a customer, merging duplicate records, or reassigning ownership opens a modal. These are decisions that require the user's full attention and resolution. They're brief, they're self-contained, and they genuinely earn the interruption. No content here — just a decision and its confirmation.
Four containers, four distinct contracts, all used correctly within the same workflow. The user always knows where they are, what's behind them, and what's possible from here.
The Decision Framework
When choosing a container, answer these questions in order:
1. Is this a decision or an alert? If yes → modal. If no → continue.
2. Is the content a first-class entity with its own identity and depth? If yes → route. If no → continue.
3. Is the user's current view the primary context, and is this content a detail within it? If yes, and the content fits within constrained space → panel. If no → continue.
4. Is this content a facet of the current entity, at the same level as other facets? If yes → tab, with a URL.
If none of these fit cleanly, the content itself probably needs to be reconsidered — not the container.
Summary
- Each container represents a different answer to what happens to the user's current context: suspended (modal), retained (panel), partially replaced (tab), fully replaced (route).
- Modals are for decisions and alerts, not for content. Their contract is interruption; using them for explorable content breaks that contract.
- Panels are for detail within a primary context. They have a ceiling — content that is too rich for a panel belongs in a route.
- Tabs are facets of a single parent entity. They should almost always have URLs. Content that has its own identity is a route destination, not a tab.
- Route changes are for first-class entities and primary navigation. They always deserve a URL.
- The URL test cuts across all four: if you want a URL, it's probably a route or a tab. If you don't need one, it's probably a panel or a modal.
- Multiple containers can coexist correctly in the same workflow. The CRM example uses all four simultaneously, each in its correct role.