Skip to content

refactor(ui5-shellbar): split into features#13010

Draft
dobrinyonkov wants to merge 8 commits intomainfrom
shellbar-refactor-bk
Draft

refactor(ui5-shellbar): split into features#13010
dobrinyonkov wants to merge 8 commits intomainfrom
shellbar-refactor-bk

Conversation

@dobrinyonkov
Copy link
Contributor

@dobrinyonkov dobrinyonkov commented Feb 3, 2026

Overview

The ShellBar component has been refactored from a monolithic 2000+ line file into a modular architecture with clear separation of concerns. The main ShellBar.ts component now acts as an orchestrator, delegating specific responsibilities to dedicated controller modules.

Summary

The refactoring achieves:

  1. Separation of concerns - Each module handles one aspect
  2. No circular dependencies - Callback injection pattern
  3. Testability - Modules can be unit tested independently
  4. Maintainability - ~1200 lines in ShellBar.ts vs previous ~2000
  5. Clear legacy boundary - Deprecated features isolated in ShellBarLegacy
  6. Strategy pattern - Search controllers swapped based on field type

Module Dependency Graph

                                    ┌──────────────────────┐
                                    │      ShellBar        │
                                    │   (Orchestrator)     │
                                    └──────────┬───────────┘
                                               │
               ┌───────────────┬───────────────┼───────────────┬────────────────┐
               │               │               │               │                │
               ▼               ▼               ▼               ▼                ▼
    ┌──────────────┐  ┌────────────────┐ ┌──────────┐ ┌──────────────┐ ┌─────────────┐
    │ShellBarOver- │  │ ShellBarSearch │ │ShellBar- │ │ ShellBar-    │ │ ShellBar-   │
    │    flow      │  │    (new)       │ │   Item   │ │Accessibility │ │   Legacy    │
    └──────────────┘  ├────────────────┤ │Navigation│ └──────────────┘ └─────────────┘
                      │ShellBarSearch- │ └──────────┘
                      │   Legacy       │
                      └────────────────┘
                              ▲
                              │ implements
                      ┌───────┴────────┐
                      │IShellBarSearch │
                      │  Controller    │
                      └────────────────┘

Dependency Flow Pattern

All modules follow a callback injection pattern to avoid circular dependencies:

// ShellBar passes callbacks to modules via constructor
this.overflow = new ShellBarOverflow();

this._searchAdaptor = new ShellBarSearch({
    getSearchField: () => this.search,
    getSearchState: () => this.showSearchField,
    setSearchState: (expanded) => this.setSearchState(expanded),
    getOverflowed: () => this.overflow.isOverflowing(...),
    getCSSVariable: (cssVar) => this.getCSSVariable(cssVar),
});

Key principle: Modules receive getter/setter callbacks → modules never import ShellBar directly → no circular dependencies.

Module Responsibilities

1. ShellBar.ts (Orchestrator)

Location: packages/fiori/src/ShellBar.ts

The main component that:

  • Defines all public properties, slots, and events
  • Instantiates and coordinates all controller modules
  • Handles lifecycle methods (onBeforeRendering, onAfterRendering)
  • Builds the actions array (computed list of enabled action buttons)
  • Manages breakpoint state (S/M/L/XL/XXL)

Key state properties:

@property() breakpointSize = "S";           // Current responsive breakpoint
@property() showOverflowButton = false;     // Whether overflow button is visible
@property() overflowPopoverOpen = false;    // Overflow popover state
@property() hiddenItemsIds: string[] = [];  // IDs of items hidden due to overflow
@property() showFullWidthSearch = false;    // Full-screen search overlay state

2. ShellBarOverflow.ts

Location: packages/fiori/src/shellbar/ShellBarOverflow.ts

Handles responsive item hiding when space is insufficient.

Algorithm:

  1. Reset: show all items, hide overflow button
  2. Build sorted list of hidable items by hideOrder
  3. Loop: while isOverflowing() → hide next item
  4. If hidden item has showInOverflow: true → show overflow button
  5. Return { hiddenItemsIds, showOverflowButton }

Two hiding strategies:

Search CLOSED Search OPEN
0: Actions first 0: Content first
1000: Content 1000: Actions
2000: Search button 2000: Search button
3000: Last content item -

Flickering prevention: keepHidden flag keeps previously hidden items hidden during recalculation to prevent brief visibility flashes during resize.

3. ShellBarSearch.ts (New Search)

Location: packages/fiori/src/shellbar/ShellBarSearch.ts

Controller for ui5-shellbar-search component (self-collapsible search field).

Responsibilities:

  • Subscribe to ui5-open, ui5-close, ui5-search events
  • Auto-collapse when space is tight, expand when space is available
  • Sync collapsed/open properties with ShellBar state
  • Determine when full-screen search overlay should show

Key methods:

subscribe()      // Listen to search field events
unsubscribe()    // Remove event listeners
autoManageSearchState(hiddenItems, availableSpace)  // Auto expand/collapse
syncShowSearchFieldState()    // Push state to search field
shouldShowFullScreen()        // Check if full-screen mode needed

4. ShellBarSearchLegacy.ts

Location: packages/fiori/src/shellbar/ShellBarSearchLegacy.ts

Controller for legacy search fields (ui5-input, custom elements).

Differences from ShellBarSearch:

  • No event subscription (legacy fields don't emit events)
  • Respects disableSearchCollapse property
  • Detects value in both value property and nested <input> elements

5. IShellBarSearchController.ts (Interface)

Location: packages/fiori/src/shellbar/IShellBarSearchController.ts

Common interface for search controllers:

interface IShellBarSearchController {
    subscribe(): void;
    unsubscribe(): void;
    autoManageSearchState(hiddenItems: number, availableSpace: number): void;
    syncShowSearchFieldState(): void;
    shouldShowFullScreen(): boolean;
}

ShellBar selects controller based on search field type:

get searchAdaptor(): IShellBarSearchController {
    return this.isSelfCollapsibleSearch
        ? this._searchAdaptor      // ShellBarSearch
        : this._searchAdaptorLegacy; // ShellBarSearchLegacy
}

6. ShellBarItemNavigation.ts

Location: packages/fiori/src/shellbar/ShellBarItemNavigation.ts

Handles arrow key navigation between toolbar items.

Supported keys:

  • / - Move focus to previous/next item
  • Home - Focus first item
  • End - Focus last item

Smart input handling: Allows left/right navigation within input fields when cursor is not at edge.

7. ShellBarAccessibility.ts

Location: packages/fiori/src/shellbar/ShellBarAccessibility.ts

Centralizes ARIA attribute computation.

Provides:

  • getActionsAccessibilityAttributes() - ARIA attrs for each action button
  • getActionsRole() - Returns "toolbar" when multiple actions visible
  • getContentRole() - Returns "group" when multiple content items visible

Type exports:

ShellBarAccessibilityAttributes   // Input from app developer
ShellBarAccessibilityInfo         // Computed ARIA info for template
ShellBarLogoAccessibilityAttributes
ShellBarProfileAccessibilityAttributes
ShellBarAreaAccessibilityAttributes

8. ShellBarLegacy.ts

Location: packages/fiori/src/shellbar/ShellBarLegacy.ts

Handles deprecated features (to be removed in v3):

  • logo slot
  • primaryTitle / secondaryTitle properties
  • menuItems slot with menu popover

Lazily initialized:

private initLegacyController() {
    if (this.hasLegacyFeatures) {
        this.legacyAdaptor = new ShellBarLegacy({
            component: this,
            getShadowRoot: () => this.shadowRoot,
        });
    }
}

Template Structure

Main Template

Location: packages/fiori/src/ShellBarTemplate.tsx

<header>
    [Full-width search overlay]     ← Conditional
    [Start button slot]             ← Optional
    [Branding area]                 ← New: ui5-shellbar-branding OR Legacy
    <overflow-container>
        <overflow-container-inner>
            [Content area]          ← Start items + Spacer + End items
            [Search field]          ← New or Legacy template
            [Search button]         ← Legacy only
            [Assistant slot]
            [Notifications button]
            [Custom items]          ← ShellBarItem slots
            [Overflow button]
            [Profile button]
            [Product switch button]
        </overflow-container-inner>
    </overflow-container>
</header>
<Popover>                           ← Overflow popover
    [Hidden items list]
</Popover>

Template Modules

Template Location Purpose
ShellBarSearchTemplate.tsx shellbar/templates/ New search field + full-width overlay
ShellBarSearchLegacyTemplate.tsx shellbar/templates/ Legacy search field + button
ShellBarLegacyTemplate.tsx shellbar/templates/ Logo, titles, menu button, menu popover

CSS Organization

File Purpose
ShellBar.css Core layout, overflow container, actions
ShellBarLegacy.css Legacy branding area, menu button, titles
ShellBarSearchLegacy.css Legacy search field styling
ShellBarItem.css ShellBarItem component styles
ShellBarPopover.css Overflow and menu popover styles

Data Flow: Resize Handling

1. ResizeHandler triggers handleResize()
           │
           ▼
2. updateBreakpoint() → sets breakpointSize (S/M/L/XL/XXL)
           │
           ▼
3. updateOverflow() → calls overflow.updateOverflow({...})
           │
           ├──► Overflow module iteratively hides items
           │    until content fits
           │
           ▼
4. handleUpdateOverflowResult() → updates hiddenItemsIds, showOverflowButton
           │
           ▼
5. searchAdaptor.autoManageSearchState(hiddenItems, spacerWidth)
           │
           ├──► Auto-collapse search if space tight
           │    OR expand if space available
           │
           ▼
6. showFullWidthSearch = searchAdaptor.shouldShowFullScreen()

Type Exports

ShellBar exports types for consumers:

// Event detail types
ShellBarProfileClickEventDetail
ShellBarSearchFieldClearEventDetail
ShellBarNotificationsClickEventDetail
...

// Common types
ShellBarActionId        // "search" | "profile" | "overflow" | ...
ShellBarActionItem      // Action configuration object
ShellBarBreakpoint      // "S" | "M" | "L" | "XL" | "XXL"

// Accessibility types (re-exported from ShellBarAccessibility)
ShellBarAccessibilityAttributes
ShellBarAccessibilityInfo
...

// Legacy types (marked for removal)
ShellBarLogoClickEventDetail
ShellBarMenuItemClickEventDetail

@ui5-webcomponents-bot
Copy link
Collaborator

ui5-webcomponents-bot commented Feb 3, 2026

@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview February 3, 2026 20:55 Inactive
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview February 3, 2026 21:17 Inactive
@dobrinyonkov dobrinyonkov marked this pull request as draft February 4, 2026 10:03
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview February 4, 2026 11:38 Inactive
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview February 4, 2026 20:17 Inactive
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview February 5, 2026 07:57 Inactive
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview February 5, 2026 08:46 Inactive
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants