Skip to content

Pending Review

Pending Review from User Experience (UX)

Expand Container Component

Overview

The PWC Expand Container is a layout component in the Progress Web Components design system that provides conditional content visibility based on expand context state. It works in conjunction with expand context providers to create collapsible content sections and accordion-style interfaces across React and Angular applications.

Core Capabilities

  • Context-Driven Visibility - Automatically shows or hides content based on expand context state without manual state management
  • Seamless Integration - Works with expand context providers to create cohesive expand/collapse functionality
  • Slot-Based Content - Flexible content rendering through slot-based architecture supporting any child components
  • Performance Optimized - Conditional rendering prevents unnecessary DOM elements when content is collapsed
  • Framework Agnostic - Consistent behavior across React, Angular, and Pure JavaScript implementations
  • Accessibility Support - Proper content visibility handling that works with screen readers and keyboard navigation

When to use Expand Container:

  • Create collapsible content sections within cards, panels, or sidebar layouts
  • Build accordion interfaces where multiple sections can expand and collapse independently
  • Implement progressive disclosure patterns for detailed information or advanced options
  • Develop expandable table rows or list items with additional details

When not to use Expand Container:

  • Simple show/hide functionality that doesn't require context-based state management
  • Modal dialogs or overlays that need different visibility and positioning behavior
  • Static content that should always be visible regardless of interaction state

Basic Implementation

import React, { useState } from 'react';
import { PwcExpandContainer, PwcExpandContext, PwcExpander } from "@progress-i360/pwc-react";

function AccordionExample() {
  const [expanded, setExpanded] = useState(false);

  return (
      <div style={{ maxWidth: '400px', border: '1px solid #ddd', borderRadius: '8px' }}>
        <PwcExpandContext expanded={expanded}>
          <div style={{ padding: '16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer' }}
               onClick={() => setExpanded(!expanded)}>
            <h4>FAQ: Reset Password</h4>
            <PwcExpander />
          </div>

          <PwcExpandContainer>
            <div style={{ padding: '16px', borderTop: '1px solid #ddd' }}>
              <p>Click "Forgot Password" and check your email for reset instructions.</p>
            </div>
          </PwcExpandContainer>
        </PwcExpandContext>
      </div>
  );
}
import { useState } from 'react';
import '@progress-i360/progress-web-components/expand-context';
import '@progress-i360/progress-web-components/expand-container';
import '@progress-i360/progress-web-components/expander';
import '@progress-i360/progress-web-components/button';

function SettingsAccordion() {
  const [activeSection, setActiveSection] = useState<string | null>(null);
  const sections = ['Account', 'Privacy', 'Advanced'];

  return (
      <div style={{ maxWidth: '400px', border: '1px solid #ddd', borderRadius: '8px' }}>
        {sections.map((section) => (
          <pwc-expand-context key={section} expanded={activeSection === section}>
            <div 
              style={{ padding: '16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', borderBottom: '1px solid #eee' }}
              onClick={() => setActiveSection(activeSection === section ? null : section)}
            >
              <h4>{section} Settings</h4>
              <pwc-expander></pwc-expander>
            </div>

            <pwc-expand-container>
              <div style={{ padding: '16px' }}>
                <p>Configure your {section.toLowerCase()} options here.</p>
                <pwc-button label="Save Changes" variant="primary"></pwc-button>
              </div>
            </pwc-expand-container>
          </pwc-expand-context>
        ))}
      </div>
  );
}
{
  title: 'Account Settings',
  icon: '👤',
  content: (
    <div style={{ padding: '16px' }}>
      <div style={{ marginBottom: '12px' }}>
        <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
          Display Name
        </label>
        <input 
          type="text" 
          defaultValue="John Doe"
          style={{ 
            width: '100%', 
            padding: '8px 12px',
            border: '1px solid #ddd',
            borderRadius: '4px'
          }}
        />
      </div>
      <div style={{ marginBottom: '12px' }}>
        <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
          Email Address
        </label>
        <input 
          type="email" 
          defaultValue="john.doe@example.com"
          style={{ 
            width: '100%', 
            padding: '8px 12px',
            border: '1px solid #ddd',
            borderRadius: '4px'
          }}
        />
      </div>
      <button style={{
        padding: '8px 16px',
        backgroundColor: '#007bff',
        color: 'white',
        border: 'none',
        borderRadius: '4px',
        cursor: 'pointer'
      }}>
        Save Changes
      </button>
    </div>
  )
},
{
  title: 'Privacy Settings',
  icon: '🔒',
  content: (
    <div style={{ padding: '16px' }}>
      <div style={{ marginBottom: '16px' }}>
        <label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
          <input type="checkbox" />
          <span>Make profile public</span>
        </label>
      </div>
      <div style={{ marginBottom: '16px' }}>
        <label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
          <input type="checkbox" defaultChecked />
          <span>Allow email notifications</span>
        </label>
      </div>
      <div style={{ marginBottom: '16px' }}>
        <label style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
          <input type="checkbox" />
          <span>Share analytics data</span>
        </label>
      </div>
    </div>
  )
},
{
  title: 'Advanced Options',
  icon: '⚙️',
  content: (
    <div style={{ padding: '16px' }}>
      <div style={{ marginBottom: '12px' }}>
        <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
          API Access Level
        </label>
        <select style={{ 
          width: '100%', 
          padding: '8px 12px',
          border: '1px solid #ddd',
          borderRadius: '4px'
        }}>
          <option>Read Only</option>
          <option>Read/Write</option>
          <option>Full Access</option>
        </select>
      </div>
      <div style={{ marginBottom: '16px' }}>
        <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
          Session Timeout (minutes)
        </label>
        <input 
          type="number" 
          defaultValue="30"
          min="5"
          max="120"
          style={{ 
            width: '100%', 
            padding: '8px 12px',
            border: '1px solid #ddd',
            borderRadius: '4px'
          }}
        />
      </div>
      <div style={{ 
        padding: '12px',
        backgroundColor: '#fff3cd',
        border: '1px solid #ffeaa7',
        borderRadius: '4px',
        fontSize: '14px'
      }}>
        ⚠️ Advanced settings may affect system performance
      </div>
    </div>
  )
}

];

return (

Settings

{settingsSections.map((section, index) => ( <div style={{ padding: '16px', backgroundColor: '#f8f9fa', borderBottom: index < settingsSections.length - 1 ? '1px solid #e0e0e0' : 'none', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }} onClick={(e) => { const context = e.currentTarget.closest('pwc-expand-context'); context?.toggleExpanded(); }} >
{section.icon}

{section.title}

        <pwc-expand-container>
          <div style={{ backgroundColor: 'white' }}>
            {section.content}
          </div>
        </pwc-expand-container>
      </pwc-expand-context>
    ))}
  </div>
</div>

); } ```

```typescript import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';

import '@progress-i360/progress-web-components/expand-context'; import '@progress-i360/progress-web-components/expand-container'; import '@progress-i360/progress-web-components/expander'; import '@progress-i360/progress-web-components/button';

@Component({
  selector: 'expand-container-demo',
  template: `
      <pwc-expand-context [expanded]="isExpanded">
      <h3>{{sectionTitle}}</h3>
      <pwc-expander (click)="toggle()"></pwc-expander>
      <pwc-expand-container>
        <p>{{expandedContent}}</p>
        <pwc-button label="Change Content" (pwc-click)="changeContent()"></pwc-button>
      </pwc-expand-container>
    </pwc-expand-context>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class ExpandContainerDemo {
  isExpanded = false;
  sectionTitle = 'Click to Expand';
  expandedContent = 'This content is now visible!';

  toggle() {
    this.isExpanded = !this.isExpanded;
    this.sectionTitle = this.isExpanded ? 'Click to Collapse' : 'Click to Expand';
  }

  changeContent() {
    const contents = [
      'Updated content with new information.',
      'Here is some different text to display.',
      'Content has been changed successfully!',
      'This demonstrates dynamic content updates.'
    ];
    this.expandedContent = contents[Math.floor(Math.random() * contents.length)];
  }
}
```
// Create expand context wrapper
const context = document.createElement('pwc-expand-context');
context.setAttribute('expanded', 'false');

// Create clickable header
const header = document.createElement('div');
header.textContent = 'Click to expand content';
header.style.cursor = 'pointer';
header.style.padding = '10px';
header.style.border = '1px solid #ddd';

// Create expandable container with content
const expandContainer = document.createElement('pwc-expand-container');
expandContainer.innerHTML = '<div style="padding: 10px;">This content is now visible!</div>';

// Toggle expansion on click
header.addEventListener('click', () => {
  const isExpanded = context.getAttribute('expanded') === 'true';
  context.setAttribute('expanded', !isExpanded);
});

// Add components to context
context.appendChild(header);
context.appendChild(expandContainer);

// Add to page
document.body.appendChild(context);

Usage Patterns

  • Accordion Interfaces - Combine with expand context to create collapsible content sections in FAQ pages, settings panels, or documentation
  • Progressive Disclosure - Hide detailed information until users explicitly request it, improving initial page load and reducing cognitive load
  • Nested Navigation - Create expandable menu structures or file explorers where users can drill down into hierarchical content
  • Content Organization - Structure complex layouts where secondary information can be revealed on demand without cluttering the primary interface

Best Practices

Content Strategy Guidelines

  • Logical Grouping - Organize expandable content into meaningful sections that users would naturally expect to find together
  • Clear Headers - Provide descriptive headers for expandable sections that clearly indicate the content within
  • Progressive Enhancement - Ensure critical content is accessible even if expand functionality fails or is disabled
  • Visual Hierarchy - Use consistent spacing and styling to maintain clear relationships between expandable and static content

Performance Optimization

  • Conditional Rendering - Leverage the component's conditional rendering to prevent unnecessary DOM elements when content is collapsed
  • Context Efficiency - Use expand context efficiently to manage state across multiple containers without prop drilling
  • Lazy Loading - Consider loading complex expandable content only when needed to improve initial page performance
  • Memory Management - Clean up event listeners and resources when expand containers are unmounted or hidden

Integration Architecture

  • Context Patterns - Implement expand context at appropriate component boundaries to maintain clean separation of concerns
  • State Coordination - Coordinate expand state with other application state management systems when necessary
  • Accessibility Integration - Ensure expand containers work properly with screen readers and keyboard navigation patterns
  • Responsive Behavior - Design expandable content to work effectively across different screen sizes and device capabilities

Common Use Cases

Settings and Configuration Panels

  • Organize complex settings into expandable categories to reduce visual clutter and improve navigation
  • Create progressive disclosure patterns for advanced options that don't overwhelm casual users
  • Group related configuration options together while maintaining clean visual hierarchy

Documentation and Help Systems

  • Build collapsible FAQ sections where users can find specific answers without scrolling through all content
  • Create expandable code examples or detailed explanations that don't interfere with scanning
  • Organize troubleshooting guides with expandable steps for different scenarios

Data Presentation and Dashboards

  • Implement expandable table rows or list items that reveal additional details on demand
  • Create collapsible widget sections in dashboards to maximize screen real estate usage
  • Build drill-down interfaces for data exploration and analysis workflows

Troubleshooting

Common Issues

Content Not Expanding

Problem: Expand container content doesn't show when expand context is triggered.

Solution:

  • Verify that the expand container is properly nested within an expand context provider. Check that the expand context is correctly managing state and that the expanded property is being updated. Ensure the expand container's slot content is properly structured.

Context State Not Updating

Problem: Multiple expand containers don't respond to context changes or update inconsistently.

Solution:

  • Confirm that all expand containers are within the same expand context scope. Verify that the context provider is properly managing state updates and broadcasting changes to all consumers. Check for any conflicting state management or event handling.

Performance Issues with Large Content

Problem: Expanding containers with complex content causes lag or performance degradation.

Solution:

  • Implement lazy loading for complex expandable content. Consider virtualizing large lists or data sets within expand containers. Optimize re-rendering by using proper React keys or Angular trackBy functions for dynamic content.

Accessibility Problems

Problem: Screen readers or keyboard navigation don't work properly with expandable content.

Solution:

  • Ensure proper ARIA attributes are set on expand triggers and containers. Verify that keyboard focus management works correctly when content expands and collapses. Test with screen readers to confirm that state changes are properly announced.

Implementation Support

  • Context Integration - Comprehensive examples showing how to coordinate expand containers with expand context providers across different scenarios
  • Framework Patterns - Best practices for implementing expand containers in React hooks, Angular services, and vanilla JavaScript applications
  • Performance Guidelines - Optimization strategies for handling complex or dynamic content within expandable sections

Resources

Storybook Documentation

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


This guide provides high-level implementation guidance. For detailed API specifications and interactive examples, visit our Storybook documentation.