Role-Based Sidebar Navigation in React Applications
Building dynamic sidebars is far from trivial. A maintainable and scalable solution requires a modern, well-structured approach — especially when dealing with multiple user roles and navigation scenarios. Without solid architecture, hardcoded components quickly become unmanageable as your application grows. Instead of relying on hardcoded items, you can define a sidebar configuration as data and render items dynamically based on user roles. Here’s a clean and extensible approach using TypeScript: type SidebarItem = { id: string title: string icon: keyof typeof Icons to: string allowedRoles: UserRole[] activeUrls?: string[] } const sidebarItems: SidebarItem[] = [ { id: "dashboard", title: t("labels.dashboard"), icon: "dashboard", to: "/dashboard", allowedRoles: [UserRole.COLLABORATOR, UserRole.USER, UserRole.WORKER], }, { id: "myJobs", title: t("labels.myJobs"), icon: "briefcase", to: "/my-jobs/current", activeUrls: ["/my-jobs/current", "/my-jobs/draft", "/my-jobs/completed"], allowedRoles: [UserRole.COLLABORATOR, UserRole.USER, UserRole.WORKER], }, { id: "exploreServices", title: t("labels.exploreServices"), icon: "search", to: "/post-a-job", allowedRoles: [UserRole.USER], }, { id: "myProfile", title: t("labels.myProfile"), icon: "user", to: "/my-profile", allowedRoles: [UserRole.WORKER], }, ] The SidebarItem type defines each item's structure — including id, title, icon, destination route (to), and the allowedRoles that determine visibility. The optional activeUrls helps match nested routes to highlight the correct item.

Building dynamic sidebars is far from trivial. A maintainable and scalable solution requires a modern, well-structured approach — especially when dealing with multiple user roles and navigation scenarios. Without solid architecture, hardcoded components quickly become unmanageable as your application grows.
Instead of relying on hardcoded items, you can define a sidebar configuration as data and render items dynamically based on user roles. Here’s a clean and extensible approach using TypeScript:
type SidebarItem = {
id: string
title: string
icon: keyof typeof Icons
to: string
allowedRoles: UserRole[]
activeUrls?: string[]
}
const sidebarItems: SidebarItem[] = [
{
id: "dashboard",
title: t("labels.dashboard"),
icon: "dashboard",
to: "/dashboard",
allowedRoles: [UserRole.COLLABORATOR, UserRole.USER, UserRole.WORKER],
},
{
id: "myJobs",
title: t("labels.myJobs"),
icon: "briefcase",
to: "/my-jobs/current",
activeUrls: ["/my-jobs/current", "/my-jobs/draft", "/my-jobs/completed"],
allowedRoles: [UserRole.COLLABORATOR, UserRole.USER, UserRole.WORKER],
},
{
id: "exploreServices",
title: t("labels.exploreServices"),
icon: "search",
to: "/post-a-job",
allowedRoles: [UserRole.USER],
},
{
id: "myProfile",
title: t("labels.myProfile"),
icon: "user",
to: "/my-profile",
allowedRoles: [UserRole.WORKER],
},
]
The SidebarItem
type defines each item's structure — including id
, title
, icon
, destination route (to
), and the allowedRoles
that determine visibility. The optional activeUrls
helps match nested routes to highlight the correct item.