Good admin panel design gets hard the moment a second kind of user logs in. An owner wants billing and settings. A manager wants their team’s records and approvals. The support agent is a different case again, because they need to find one customer fast and would rather not be able to change anything. Design one screen, hide buttons at the end, and you get a panel that confuses everyone and leaks access in places nobody tested.
For 7+ years I’ve designed dashboards, admin panels and internal tools for B2B SaaS and AI teams, across healthcare, fintech, HR, e-commerce and operations. Almost every one had several roles, and the requirements kept changing. This is the process I use now. It’s a companion to my broader guide to SaaS dashboard design and sticks to one question: what each person can see and change, and what happens when they reach something they can’t.
What makes admin panel design hard with multiple user roles?
Each role sees a different version of the same product, and every version has to make sense on its own. A Viewer’s table with three columns should look finished, as if someone designed it for them on purpose. An empty state should tell a Manager whether there’s no data yet or whether they lack access to it.
Roles also tend to change after launch. A client adds a “Regional Manager” six months in, or splits “Admin” into “Admin” and “Billing”. If permissions were baked into individual screens, every new role means redesigning those screens. If they live in a matrix and a small set of component states, adding a role mostly means adding a column and checking the states it touches. One of my clients added a new role after launch, which is why I keep permissions in the matrix instead of in the screens.
How do you define user roles before designing screens?
List jobs, then group them into roles
I start with a list of jobs, written as verbs on objects: “approve a refund”, “invite a teammate”, “export candidates”, “edit pricing”. Most of them come from discovery calls and support tickets, and the rest from whoever currently does the work in a spreadsheet. Then I group the jobs by who does them, and each group becomes a role.
I don’t start from job titles, because they vary between customers. One company’s “Manager” approves spend and another’s only views reports. “Approve a refund” means the same thing in every account, so roles built from jobs hold up when you sell to the next customer.
Keep the first version small
Most early-stage products need four or five roles at launch, and I’d rather launch with too few than too many. My own clients’ MVPs usually launch with three to five. The recruitment CRM platform I designed for HRT Limited had three: Admin, Recruiter and Hiring manager.
Each extra role multiplies the states you have to design and then support. If two roles differ by one permission, merge them and add that permission as a toggle later.
Start with a roles-and-permissions matrix
Before I open Figma, I write the matrix. Engineering and QA end up working from it as much as I do, and it’s the document I update when requirements change. It also keeps scoping honest. Count the cells that aren’t “None” and you have a decent proxy for how many states need designing, which feeds straight into what it costs to hire a SaaS product designer for the project.
The matrix (copy this)
Paste this into Notion as a table, or into a Figma table component, and rename the rows to your product’s objects.
| Area / action | Owner | Admin | Manager | Member | Viewer | Billing |
|---|---|---|---|---|---|---|
| View dashboard metrics | All | All | Own team | Own records | All (read) | None |
| View records (list + detail) | All | All | Own team | Own + assigned | All (read) | None |
| Create records | Yes | Yes | Own team | Yes | No | No |
| Edit records | All | All | Own team | Own only | No | No |
| Delete records | Yes | Yes (with confirm) | No, archive only | No | No | No |
| Bulk actions / import | Yes | Yes | Own team | No | No | No |
| Export data | Yes | Yes | Own team | No | No | No |
| Approve / reject workflow steps | Yes | Yes | Own team | No | No | No |
| Invite users | Yes | Yes | Own team, Member role only | No | No | No |
| Change user roles | Yes | Up to Admin | No | No | No | No |
| Remove users | Yes | Yes, except Owner | No | No | No | No |
| Workspace settings | Yes | Yes | No | No | No | No |
| Integrations / API keys | Yes | Yes | No | No | No | No |
| Billing and invoices | Yes | View only | No | No | No | Yes |
| Change plan / payment method | Yes | No | No | No | No | Yes |
| Audit log | Yes | Yes | Own team | No | No | No |
| Transfer ownership / delete workspace | Yes | No | No | No | No | No |
How to read and extend it
Every cell uses one of a few values: All, Own team, Own records, Read, or None. I keep the vocabulary this short so engineers can read any cell without asking me what it means. “Own team” and “Own records” are scopes, and they matter as much as the yes/no. A Manager who can edit records needs to know which records, and the UI has to show that scope somewhere visible.
When a client asks for a new role, I copy the closest existing column and change only the cells that differ, and those cells become my list of screens and states to design.
What should each role see, hide, and never be able to do?
The matrix covers what’s allowed. How that shows up on screen differs a lot by role.
Owner
Sees everything. “Transfer ownership” and “Delete workspace” live in a danger zone at the bottom of settings, behind typed confirmation. There is always exactly one Owner, so the UI blocks removing or demoting the last one.
Admin
Sees the full product and all settings except plan changes and ownership. Admins can assign roles up to their own level, so the role dropdown doesn’t offer “Owner” at all. They see billing in read-only form, because they’re often the ones answering “why did our invoice go up”.
Manager
Sees their team’s records and metrics by default, with the scope labelled in the page header (“Showing: Sales Team, 14 people”). Settings and integrations are hidden from navigation. Managers can’t delete anything permanently. They archive, and an Admin restores or purges. That rule prevents most of the “who deleted this” support tickets I’ve seen products struggle with.
Member
Sees their own and assigned records, and a dashboard scoped to their own work. Navigation is short, usually their workspace and queue plus a profile link. Members never see other people’s performance numbers unless the product is built around shared visibility. Bulk actions and export are hidden, since a Member with export can download the whole customer list.
Viewer
Sees the same screens as an Admin in read-only form. Edit buttons are removed entirely. Form fields render as plain text and tables drop their checkbox column. I want a Viewer screen to look calm and finished, and a screen full of greyed-out buttons makes the person feel like a guest who wandered into the wrong room.
Billing contact
Sees billing, invoices, plan and payment method only, because finance people need invoices without access to customer data. They land straight on the billing screen.
Should you hide or disable features a user can’t access?
I hide what a role will never use, and I disable (with a reason) anything a role might reasonably expect to use.
A Billing contact doesn’t need to know integrations exist, so that menu item is hidden. A Manager looking at a record they can view but not edit expects an Edit button, so I show a disabled one with a tooltip: “Only Admins can edit records outside your team.” If I hid it, they’d assume the feature was broken and file a ticket.
Plan-gated features are the exception, and I show them to everyone. Whoever can upgrade gets an upgrade prompt, and everyone else gets an “Ask your Owner” note.
How to design locked and empty states for role-based access UI
Four states that look alike but mean different things
An empty table can mean four different things, and each needs its own design:
| State | What the user sees | Primary action |
|---|---|---|
| No data yet | Illustration or icon, one line on what will appear here | Create first record (if allowed) |
| Filtered to nothing | “No results for these filters” | Clear filters |
| No access | Lock icon, who controls access, what this area is for | Request access |
| Out of scope | “These records belong to other teams” | Switch scope (if allowed) or none |
One generic “Nothing here” component leaves users guessing which of these they’re looking at. I design them as variants of a single empty-state component in Figma, with a role and a reason property. Engineers pick the right one by passing two values.
Copy patterns for locked states
Locked-state copy should say who controls the area and what to do next, in two lines at most:
- “Integrations are managed by Admins. Ask {Admin name} or another Admin to connect a new tool.” [Request access]
- “Exports are turned off for your role. An Admin can turn them on in Settings > Roles.”
When the product knows who the Admins are, name a real person. “Contact your administrator” sends people hunting, and they usually end up asking support.
Admin dashboard UX patterns that keep roles from colliding
I add a few patterns to almost every multi-role admin panel. The first is a scope label: every list and dashboard states its scope in the header, so two people comparing numbers on a call know why theirs differ.
Admins also get a “view as” mode. They can preview the product as any role without logging out, which answers most permission questions before they reach support.
Then there’s the audit log, which records who changed what, when, and from which role. Healthcare and fintech products usually require one, and it should be searchable by person and by record.
Last, the invite flow describes each role. Every option in the invite dropdown shows a one-line summary of what that role can do. When a role is just a name, people pick the bigger one to be safe and over-grant access.
How to hand off role-based screens to developers
Engineers enforce permissions on the server. My job is to make every visible state explicit, so nobody has to improvise one during the build. My handoff for a multi-role admin panel usually includes:
- The permissions matrix, linked from the Figma file cover page.
- Component variants with a
roleorstateproperty (default, read-only, disabled with reason, hidden). - One prototype flow per role for the main jobs, with a role switcher on the first frame.
- Annotations on any element whose visibility depends on scope, naming the permission it maps to.
When a new role turns up later, it costs one new matrix column and a few property values.
FAQ
How many user roles should an admin panel have? Most early-stage B2B products launch well with four or five: Owner, Admin, Manager, Member and Viewer, plus Billing if finance teams buy the product. Add roles when real customers ask for them, and only if the new role differs by more than one permission.
What’s the difference between roles and permissions? A permission is one action on one object, such as “export records”. A role is a named bundle of permissions you assign to people. Show roles in the UI and keep permissions in the matrix.
Should a read-only user see the same screens as an admin? Usually yes, with edit controls removed. Viewers often need the full picture for reporting or audits, and a shared layout makes it easy to discuss the same screen with colleagues.
When should I let customers create custom roles? When several customers ask for combinations your fixed roles can’t cover. A custom-role editor with grouped permissions and a preview is a design project of its own, so start with fixed roles and a few toggles.
Need help designing your admin panel?
If you’re building a B2B product with several roles and requirements that keep moving, I can map the roles and write the matrix with you, then design the screens and components your engineers will build from. A full dashboard with roles and a component system takes 3 to 6 weeks. You can see more of my work on my portfolio homepage.
Book a free intro call and tell me who uses your product. We’ll work out which roles you actually need first.



