Skip to Content

Shell

A component with a collapsible sidebar, theme and language toggles, and optional OAuth2 authentication.

Minimal Header Variant

Use the variant="minimal" prop to render a horizontal header layout instead of the default sidebar.

Features

  • Collapsible Sidebar: Icon-only collapsed mode with smooth spring animations, built on the shadcn sidebar primitives
  • Sub-Navigation: Collapsible menu items with nested sub-items that auto-expand when active
  • Collapsed Menu Handling: Clicking a collapsible item while collapsed expands the sidebar and opens the submenu
  • Custom Logo: Support for company logos with separate light/dark mode variants
  • Optional OAuth2 Authentication: Plug-and-play authorization code flow with PKCE
  • Theme Toggle: Built-in light/dark mode support
  • Language Toggle: Built-in language switcher for internationalization
  • User Profile: Dropdown menu with user information and sign-out

Installation

npx shadcn@latest add @uipath/shell

Usage

The shell works out of the box without authentication. Just provide layout props:

import { Home, Settings } from 'lucide-react'; import { ApolloShell } from '@/components/ui/shell'; const navItems = [ { path: '/dashboard', label: 'dashboard', icon: Home }, { path: '/settings', label: 'settings', icon: Settings, subItems: [ { path: '/settings', label: 'settings' }, { path: '/settings/team', label: 'team' }, ], }, ]; function App() { return ( <ApolloShell companyName="Your Company" productName="Your Product" navItems={navItems} > <YourApp /> </ApolloShell> ); }

Adding Authentication

To enable built-in OAuth2 authentication with PKCE, wrap the shell with ShellAuthProvider. Both ShellAuthProvider and ApolloShell must be inside a QueryClientProvider from @tanstack/react-query.

When a ShellAuthProvider is present, the shell automatically shows a login screen until the user is authenticated.

import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { Home, Settings } from 'lucide-react'; import { ApolloShell } from '@/components/ui/shell'; import { ShellAuthProvider } from '@/components/ui/shell-auth-provider'; const queryClient = new QueryClient(); const navItems = [ { path: '/dashboard', label: 'dashboard', icon: Home }, { path: '/settings', label: 'settings', icon: Settings, subItems: [ { path: '/settings', label: 'settings' }, { path: '/settings/team', label: 'team' }, ], }, ]; function App() { return ( <QueryClientProvider client={queryClient}> <ShellAuthProvider clientId="your-client-id" scope="openid profile email offline_access" baseUrl={window.location.origin} > <ApolloShell companyName="Your Company" productName="Your Product" navItems={navItems} > <YourApp /> </ApolloShell> </ShellAuthProvider> </QueryClientProvider> ); }

Gating access by group membership

Use GroupMembershipGuard to restrict the application to members of one or more UiPath Identity groups. The guard fetches each configured group in parallel, compares the signed-in user’s email against the combined member list, and renders either a loading indicator or an access-denied screen with a sign-out action. When the user is a member of any of the listed groups, the children render unchanged. An empty groupIds array denies access. Fetch failures bubble up to the nearest error boundary.

The toggle below switches between the loading, denied, and granted states using stubbed authentication and pre-populated query data.

Place GroupMembershipGuard inside ShellAuthProvider so it can read the authenticated user from useAuth. The baseUrl, orgName, orgId, and each groupId in groupIds compose the Identity API URL ({baseUrl}/{orgName}/identity_/api/Group/{orgId}/{groupId}):

import { GroupMembershipGuard } from '@/components/ui/shell/group-membership-guard'; function App() { return ( <QueryClientProvider client={queryClient}> <ShellAuthProvider clientId="your-client-id" scope="openid profile email offline_access" baseUrl={window.location.origin} > <GroupMembershipGuard baseUrl="https://staging.uipath.com" orgName="your-org" orgId="your-org-id" groupIds={['admins-group-id', 'editors-group-id']} > <ApolloShell companyName="Your Company" productName="Your Product" navItems={navItems} > <YourApp /> </ApolloShell> </GroupMembershipGuard> </ShellAuthProvider> </QueryClientProvider> ); }