Skip to content

LayoutHeaderPanel

Paulo Gomes da Cruz Junior edited this page Apr 13, 2026 · 1 revision

LayoutHeaderPanel

The LayoutHeaderPanel component is a slide-out panel that displays user profile information and preferences. It appears from the right side of the screen when the user clicks the profile button in the header.

Props

This component does not accept any props. It manages its own state through context hooks.

Usage

import { LayoutHeaderPanel } from "@/components/Layout/LayoutHeaderPanel";

// Typically used within LayoutHeader
<Header>
  <LayoutHeaderPanel />
</Header>;

Features

Slide-Out Panel

  • Slides in from the right side of the screen
  • Smooth transition animation
  • Overlay for focus management

Close Mechanisms

  1. Close Button: IconButton with X icon in the header
  2. Outside Click: Click anywhere outside the panel to close
  3. Keyboard: ESC key support (via Carbon)

Profile Content

The panel displays the HeaderPanelProfile component, which includes:

  • User information
  • Avatar display
  • Client/district selection
  • Logout option

Structure

<HeaderPanel expanded={isHeaderPanelOpen}>
  <div className="right-title-section">
    <h4>My Profile</h4>
    <IconButton onClick={closeHeaderPanel}>
      <Close />
    </IconButton>
  </div>
  <HeaderPanelProfile />
</HeaderPanel>

State Management

Layout Context

const { isHeaderPanelOpen, closeHeaderPanel } = useLayout();
  • isHeaderPanelOpen: Boolean controlling panel visibility
  • closeHeaderPanel: Function to close the panel

Outside Click Detection

Uses the useOutsideClick hook to detect clicks outside the panel:

const panelRef = useRef<HTMLDivElement>(null);
useOutsideClick(panelRef, closeHeaderPanel, isHeaderPanelOpen);

Conditional Rendering

The component returns null when closed to avoid rendering unnecessary DOM elements:

if (!isHeaderPanelOpen) return null;

Styling

Panel Container

.profile-panel {
  max-inline-size: 25rem !important;
  inline-size: auto;
  background-color: var(--#{vars.$bcgov-prefix}-layer-02);
  color: var(--#{vars.$bcgov-prefix}-text-primary);
  transition: width 0.11s cubic-bezier(0.2, 0, 1, 0.9);
  will-change: width;
  border-left: 0.063rem solid var(--#{vars.$bcgov-prefix}-border-subtle-01);
  display: flex;
  flex-direction: column;
}

Title Section

.right-title-section {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
}

Responsive Design

@include breakpoint-down(md) {
  .profile-panel {
    max-inline-size: 20rem !important;
  }
}

Design Tokens

  • Background: var(--bcgov-layer-02) (BC Government design token)
  • Text color: var(--bcgov-text-primary) (BC Government design token)
  • Border: var(--bcgov-border-subtle-01) (BC Government design token)
  • Max width: 25rem (desktop), 20rem (mobile)

Animation

Slide-In Effect

The panel uses Carbon's built-in slide animation:

  • Duration: 0.11s
  • Easing: cubic-bezier(0.2, 0, 1, 0.9)
  • Property: width
  • Performance: Uses will-change: width

Accessibility

ARIA Labels

aria-label="User Profile Tab"

Test ID

data-testid="header-panel"

Keyboard Support

  • Close button is keyboard accessible
  • Panel can be closed with ESC key (Carbon default)
  • Focus is properly managed when opening/closing

Focus Management

  • Ref attached for outside click detection
  • Focus trap within panel when open
  • Returns focus to trigger button on close

Close Button

Configuration

<IconButton
  kind="ghost"
  label="Close"
  onClick={closeHeaderPanel}
  align="bottom"
>
  <Close />
</IconButton>
  • Kind: Ghost (transparent background)
  • Label: "Close" (for accessibility)
  • Align: Bottom (tooltip alignment)
  • Icon: Close (X icon from Carbon)

Outside Click Hook

The component uses useOutsideClick to close the panel:

useOutsideClick(
  panelRef, // Reference to panel element
  closeHeaderPanel, // Callback to execute
  isHeaderPanelOpen, // Only active when panel is open
);

Dependencies

Required Context Providers

  • LayoutProvider: For panel state management
  • AuthProvider: Required by HeaderPanelProfile
  • PreferenceProvider: Required by HeaderPanelProfile

Custom Hooks

  • useOutsideClick: Detects clicks outside the panel

Sub-Components

  • HeaderPanelProfile: Main profile content

Carbon Components

  • HeaderPanel: Slide-out panel container
  • IconButton: Close button
  • Close: Close icon

Integration Example

import { Header, HeaderContainer } from "@carbon/react";
import { LayoutProvider } from "@/context/layout/LayoutProvider";
import { LayoutHeaderPanel } from "@/components/Layout/LayoutHeaderPanel";

function AppHeader() {
  return (
    <LayoutProvider>
      <HeaderContainer
        render={() => (
          <Header>
            {/* Other header elements */}
            <LayoutHeaderPanel />
          </Header>
        )}
      />
    </LayoutProvider>
  );
}

User Flow

  1. User clicks profile button in header
  2. Panel slides in from the right
  3. User views profile information and preferences
  4. User can:
    • Select client/district
    • View user information
    • Log out
  5. Panel closes when:
    • User clicks close button
    • User clicks outside panel
    • User presses ESC key

Related Components

  • LayoutHeader: Parent header component
  • LayoutHeaderGlobalBar: Contains the profile button that opens the panel
  • HeaderPanelProfile: Profile content displayed in the panel

Best Practices

  1. Single Instance: Use only one panel per application
  2. Context Provider: Ensure LayoutProvider is available
  3. Outside Click: Don't add multiple outside click handlers
  4. Performance: Panel unmounts when closed to save resources
  5. Accessibility: Maintain focus management and keyboard support

Notes

  • The panel slides in from the right side on all screen sizes
  • Width adjusts for mobile devices (20rem vs 25rem)
  • The panel is removed from DOM when closed (not just hidden)
  • Uses Carbon Design System patterns for consistency
  • Border provides visual separation from main content

Waste Plus Wiki

Home

Architecture

Codes

Decisions

Knowledge Base

Development

Changes

Clone this wiki locally