Skip to content

Pending Review

Pending Review from User Experience (UX)

Mode Viewer Component

Overview

The PWC Mode Viewer is a dynamic content switching component in the Progress Web Components design system that allows seamless transitions between different view modes based on user selection or application state. It provides a flexible architecture for displaying context-sensitive content and functionality across React and Angular applications.

Core Capabilities

  • Dynamic View Switching - Seamlessly switch between different content views based on mode selection without page reloads
  • Flexible Content Architecture - Support for complex nested components within each view mode using the RenderProps system
  • Event-Driven Mode Control - Provides setter functions through custom events for external mode management and control
  • Multiple View Support - Handle unlimited number of view modes with independent content and component structures
  • Component Composition - Each view can contain any combination of PWC components including layouts, forms, and data components
  • State Management Integration - Easy integration with application state management for persistent mode selection

When to use Mode Viewer:

  • Create tabbed interfaces where each tab displays different content or functionality
  • Build dashboard views that switch between different data visualizations or reporting modes
  • Implement settings panels with different configuration sections accessible through mode switching
  • Develop content management interfaces where users can switch between editing, preview, and publishing modes

When not to use Mode Viewer:

  • Simple show/hide functionality where basic conditional rendering would be more appropriate
  • Single-view interfaces that don't require mode-based content switching
  • Cases where routing-based navigation would provide better user experience and URL management

Basic Implementation

import React, { useState } from 'react';
import { PwcModeViewer, PwcButton } from "@progress-i360/pwc-react";

function TabInterface() {
  const [currentMode, setCurrentMode] = useState('overview');
  const [modeSetter, setModeSetter] = useState<((mode: string) => void) | null>(null);

  const views = {
    overview: [{ content: 'Project Overview - Welcome to the dashboard!' }],
    tasks: [{ content: 'Task List - Manage your project tasks here.' }],
    analytics: [{ content: 'Analytics - View your performance metrics.' }]
  };

  const handleModeSwitch = (mode: string) => {
    setCurrentMode(mode);
    modeSetter?.(mode);
  };

  return (
      <div style={{ maxWidth: '600px' }}>
        <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
          {Object.keys(views).map((mode) => (
            <PwcButton
              key={mode}
              label={mode}
              variant={currentMode === mode ? 'primary' : 'outline'}
              onClick={() => handleModeSwitch(mode)}
            />
          ))}
        </div>

        <div style={{ border: '1px solid #ddd', borderRadius: '8px', padding: '16px' }}>
          <PwcModeViewer
            mode={currentMode}
            views={views}
            onGetSetter={(event) => setModeSetter(() => event.detail.setter)}
          />
        </div>
      </div>
  );
}
import { useState } from 'react';
import '@progress-i360/progress-web-components/mode-viewer';
import '@progress-i360/progress-web-components/button';

function ProductTabs() {
  const [activeMode, setActiveMode] = useState('products');
  const [modeController, setModeController] = useState<((mode: string) => void) | null>(null);

  const views = {
    products: [{ content: 'Product Gallery - Browse our featured items.' }],
    orders: [{ content: 'Order Management - Track and manage orders.' }],
    analytics: [{ content: 'Sales Analytics - View performance data.' }]
  };

  const handleModeChange = (mode: string) => {
    setActiveMode(mode);
    modeController?.(mode);
  };

  return (
    <div style={{ maxWidth: '600px' }}>
      <h2>Product Management</h2>

      <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
        {Object.keys(views).map((mode) => (
          <pwc-button
            key={mode}
            label={mode}
            variant={activeMode === mode ? 'primary' : 'outline'}
            onPwcClick={() => handleModeChange(mode)}
          ></pwc-button>
        ))}
      </div>

      <div style={{ border: '1px solid #ddd', borderRadius: '8px', padding: '16px' }}>
        <pwc-mode-viewer
          mode={activeMode}
          views={views}
          onPwcGetSetter={(event) => setModeController(() => event.detail.setter)}
        ></pwc-mode-viewer>
      </div>
    </div>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/mode-viewer";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/button";

@Component({
  selector: 'mode-viewer-demo',
  template: `
    <pwc-mode-viewer [mode]="currentMode" [views]="views" (pwc-get-setter)="handleGetSetter($event)">
    </pwc-mode-viewer>
    <pwc-flex gap="s" style="margin-top: 16px;">
      <pwc-button label="Dashboard" variant="outline" (pwc-click)="switchMode('dashboard')"></pwc-button>
      <pwc-button label="Analytics" variant="outline" (pwc-click)="switchMode('analytics')"></pwc-button>
      <pwc-button label="Settings" variant="outline" (pwc-click)="switchMode('settings')"></pwc-button>
    </pwc-flex>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class ModeViewerDemo {
  currentMode = 'dashboard';

  views = {
    dashboard: [
      {
        type: 'flex',
        direction: 'column',
        gap: 'm',
        children: [
          { type: 'heading', content: 'Dashboard View' },
          { type: 'body', content: 'Overview of key metrics and data.' }
        ]
      }
    ],
    analytics: [
      {
        type: 'flex',
        direction: 'column',
        gap: 'm',
        children: [
          { type: 'heading', content: 'Analytics View' },
          { type: 'body', content: 'Detailed analytics and reports.' }
        ]
      }
    ],
    settings: [
      {
        type: 'flex',
        direction: 'column',
        gap: 'm',
        children: [
          { type: 'heading', content: 'Settings View' },
          { type: 'body', content: 'Configuration and preferences.' }
        ]
      }
    ]
  };

  switchMode(mode: string) {
    this.currentMode = mode;
  }

  handleGetSetter(e: Event) {
    const ce = (e as CustomEvent);
    // Store setter function for external mode control
  }
}
import '@progress-i360/progress-web-components/mode-viewer';
import '@progress-i360/progress-web-components/button';

const container = document.createElement('div');
container.style.maxWidth = '480px';
container.style.margin = '24px auto';
container.style.display = 'grid';
container.style.gap = '12px';

const controls = document.createElement('div');
controls.style.display = 'flex';
controls.style.gap = '8px';

const viewer = document.createElement('pwc-mode-viewer');
let modeSetter;

viewer.mode = 'overview';
viewer.views = {
  overview: [
    {
      type: 'flex',
      direction: 'column',
      gap: 's',
      children: [
        { type: 'heading', content: 'Overview' },
        { type: 'body', content: 'High-level status of key metrics.' }
      ]
    }
  ],
  analytics: [
    {
      type: 'flex',
      direction: 'column',
      gap: 's',
      children: [
        { type: 'heading', content: 'Analytics' },
        { type: 'body', content: 'Interactive charts and visualizations.' }
      ]
    }
  ],
  settings: [
    {
      type: 'flex',
      direction: 'column',
      gap: 's',
      children: [
        { type: 'heading', content: 'Settings' },
        { type: 'body', content: 'Configure preferences and notifications.' }
      ]
    }
  ]
};

viewer.addEventListener('pwc-get-setter', event => {
  modeSetter = event.detail.setter;
});

['overview', 'analytics', 'settings'].forEach(key => {
  const button = document.createElement('pwc-button');
  button.setAttribute('label', key);
  button.setAttribute('variant', key === 'overview' ? 'primary' : 'outline');
  button.addEventListener('pwc-click', () => {
    viewer.mode = key;
    modeSetter?.(key);
    Array.from(controls.children).forEach(child => {
      child.setAttribute('variant', child.getAttribute('label') === key ? 'primary' : 'outline');
    });
  });
  controls.appendChild(button);
});

container.appendChild(controls);
container.appendChild(viewer);
document.body.appendChild(container);

Usage Patterns

  • Tabbed Interface Implementation - Create multi-tab interfaces where each tab shows different content areas without page navigation
  • Dashboard Mode Switching - Build analytics dashboards that can switch between different data views and visualization modes
  • Settings Panel Organization - Organize complex settings into different modes for better user experience and logical grouping
  • Content Management Views - Implement content editing interfaces with modes for editing, preview, and publishing workflows

Best Practices

Content Strategy Guidelines

  • Logical Mode Organization - Group related functionality and content into coherent modes that make sense from a user workflow perspective
  • Consistent View Structure - Maintain consistent layout patterns and component usage across different modes for predictable user experience
  • Clear Mode Indication - Provide clear visual indicators of the current active mode and easy navigation between available modes
  • Content State Management - Consider how content state persists or resets when switching between modes to maintain user context

Performance Optimization

  • Lazy View Loading - Structure views to load content only when the mode is active to improve initial render performance
  • Component Reuse - Leverage the RenderProps system efficiently to reuse common components across different view modes
  • State Management - Use the setter function pattern to manage mode state efficiently without unnecessary re-renders
  • Memory Management - Ensure proper cleanup of event listeners and resources when mode viewer components are unmounted

Integration Architecture

  • External State Integration - Connect mode viewer state with application routing or state management systems for persistence
  • Event-Driven Architecture - Utilize the custom event system for loose coupling between mode controls and mode viewer components
  • Component Composition - Design view structures that compose well with other PWC components for consistent system integration
  • Framework Compatibility - Ensure mode viewer implementations work seamlessly across React, Angular, and vanilla JavaScript applications

Common Use Cases

Dashboard and Analytics Interfaces

  • Create comprehensive analytics dashboards with different view modes for overview, detailed metrics, and reporting
  • Build business intelligence interfaces where users can switch between different data perspectives and visualization types
  • Implement monitoring dashboards with modes for real-time data, historical analysis, and alert management

Settings and Configuration Panels

  • Organize complex application settings into logical modes such as account, preferences, security, and advanced options
  • Build user profile management interfaces with modes for personal information, privacy settings, and account security
  • Create system configuration panels with modes for different administrative functions and user management

Content Management and Creation Tools

  • Develop content editing interfaces with modes for writing, preview, formatting, and publishing workflows
  • Build project management tools with modes for planning, execution, monitoring, and reporting phases
  • Implement design tools with modes for creation, editing, collaboration, and export functionality

Troubleshooting

Common Issues

Views Not Switching

Problem: Mode viewer doesn't update content when mode changes or appears to be stuck on one view.

Solution:

  • Verify that the mode property is being updated correctly and that the views object contains the expected mode keys. Check that the setter function is properly received and called. Ensure the views object structure matches the expected RenderProps format.

Setter Function Not Working

Problem: External mode controls don't affect the mode viewer or the get-setter event isn't firing.

Solution:

  • Confirm that the onGetSetter event handler is properly attached and that the setter function is stored correctly. Check that the custom event is being dispatched during component initialization. Verify that the setter function is called with the correct mode string.

View Content Not Rendering

Problem: Mode viewer container is empty or shows no content even when views are defined.

Solution:

  • Validate the views object structure and ensure each view contains properly formatted RenderProps arrays. Check that the renderCmp function can process the provided component definitions. Verify that required components are imported and available.

Performance Issues with Complex Views

Problem: Mode switching is slow or causes performance problems with complex view structures.

Solution:

  • Optimize view definitions by reducing nested component complexity. Consider lazy loading for content-heavy modes. Review component composition to ensure efficient rendering patterns. Implement proper cleanup for event listeners and resources in unmounted modes.

Implementation Support

  • RenderProps Integration - Comprehensive support for PWC component composition within mode views using the design system's render props architecture
  • Event-Driven Control - Built-in custom event system for external mode management and integration with application state systems
  • Framework Agnostic Design - Consistent behavior and API across React, Angular, and vanilla JavaScript implementations for universal adoption

Resources

Storybook Documentation

For comprehensive API documentation, interactive examples, and testing tools: 📖 View Complete API Documentation in Storybook →


For additional implementation guidance or framework-specific questions, consult the PWC Design System documentation or reach out to the component library team.