Skip to content

Pending Review

Pending Review from User Experience (UX)

Icon Component

Overview

The PWC Icon component provides a flexible and consistent way to display SVG icons throughout the application. Built on Lit web components, it supports both Carbon Design System icons and custom brand icons with comprehensive styling options, interactive capabilities, and animation support.

Core Capabilities

  • Multiple Icon Libraries - Support for Carbon Design System icons and custom brand icons
  • Comprehensive Color System - 14 semantic color variants including danger, success, warning, and info states
  • Flexible Sizing - Six size options from extra small (xs) to extra large (xxl) with responsive scaling
  • Interactive Elements - Clickable icons with hover states and custom event handling
  • Animation Support - Built-in spin animation for loading indicators and dynamic states
  • Brand Integration - Specialized brand icon support with custom dimensions and positioning

When to use Icon:

  • Visual Communication - Enhance user interface clarity with universally recognized symbols
  • Interactive Elements - Create clickable icon buttons for actions and navigation
  • Status Indicators - Display system states, notifications, and feedback with semantic colors
  • Loading States - Show progress and processing with animated spinning icons

When not to use Icon:

  • Complex Illustrations - Use dedicated image components for detailed graphics or photographs
  • Text Replacement - Avoid using icons as the sole means of conveying critical information
  • Decorative Purpose Only - Don't add icons that don't enhance functionality or understanding

Basic Implementation

import React, { useState, useCallback } from 'react';
import { PwcIcon, PwcFlex, PwcButton } from '@progress-i360/pwc-react';

function StatusIcons() {
  const [currentStatus, setCurrentStatus] = useState('idle');
  const [isLoading, setIsLoading] = useState(false);

  // React 18: useCallback for optimization
  const statusConfig = useCallback(() => {
    const configs = {
      idle: { icon: 'circle', color: 'subtle' },
      success: { icon: 'checkmark', color: 'success' },
      error: { icon: 'warning-filled', color: 'danger' },
      info: { icon: 'information', color: 'info' }
    };
    return configs[currentStatus] || configs.idle;
  }, [currentStatus]);

  const cycleStatus = useCallback(() => {
    const statuses = ['idle', 'success', 'error', 'info'];
    const currentIndex = statuses.indexOf(currentStatus);
    setCurrentStatus(statuses[(currentIndex + 1) % statuses.length]);
  }, [currentStatus]);

  const toggleLoading = useCallback(() => {
    setIsLoading(prev => !prev);
  }, []);

  const config = statusConfig();

  return (
      <PwcFlex gap="m" alignItems="center">
        <PwcIcon 
          iconKey={config.icon}
          color={config.color}
          size="l"
          clickable
          onPwcClick={cycleStatus}
        />
        <PwcIcon 
          iconKey="loading"
          spin={isLoading}
          color="info"
          size="m"
        />
        <PwcButton 
          label={`Toggle Loading`}
          variant="outline"
          onPwcClick={toggleLoading}
        />
      </PwcFlex>
  );
}
import { useCallback, useMemo, useOptimistic, useState, startTransition } from 'react';
import '@progress-i360/progress-web-components/icon';
import '@progress-i360/progress-web-components/flex';
import '@progress-i360/progress-web-components/button';

type NotificationType = 'info' | 'warning' | 'success';

type Notification = {
  id: number;
  type: NotificationType;
  read: boolean;
};

function NotificationCenter() {
  const [notifications, setNotifications] = useState<Notification[]>([
    { id: 1, type: 'info', read: false },
    { id: 2, type: 'warning', read: false },
    { id: 3, type: 'success', read: true }
  ]);

  // React 19+: Optimistic updates for instant feedback
  const [optimisticNotifications, markAsRead] = useOptimistic(
    notifications,
    (state, notificationId: number) =>
      state.map(notification =>
        notification.id === notificationId ? { ...notification, read: true } : notification
      )
  );

  const getIconConfig = useCallback((type: NotificationType, read: boolean) => {
    const configs: Record<NotificationType, { icon: string; color: string }> = {
      info: { icon: 'information', color: read ? 'subtle' : 'info' },
      warning: { icon: 'warning-filled', color: read ? 'subtle' : 'warning' },
      success: { icon: 'checkmark', color: read ? 'subtle' : 'success' }
    };
    return configs[type];
  }, []);

  const handleNotificationClick = useCallback(
    (id: number) => {
      markAsRead(id);

      startTransition(() => {
        setNotifications(prev =>
          prev.map(notification =>
            notification.id === id ? { ...notification, read: true } : notification
          )
        );
      });
    },
    [markAsRead, setNotifications]
  );

  const addNotification = useCallback(() => {
    const types: NotificationType[] = ['info', 'warning', 'success'];
    const newNotification: Notification = {
      id: Date.now(),
      type: types[Math.floor(Math.random() * types.length)],
      read: false
    };

    startTransition(() => {
      setNotifications(prev => [...prev, newNotification]);
    });
  }, [setNotifications]);

  const renderedIcons = useMemo(
    () =>
      optimisticNotifications.map(notification => {
        const config = getIconConfig(notification.type, notification.read);
        return (
          <pwc-icon
            key={notification.id}
            icon-key={config.icon}
            color={config.color}
            size="l"
            clickable="true"
            onPwcClick={() => handleNotificationClick(notification.id)}
          ></pwc-icon>
        );
      }),
    [getIconConfig, handleNotificationClick, optimisticNotifications]
  );

  return (
    <pwc-flex direction="column" gap="s">
      <pwc-flex gap="s" align-items="center" wrap="wrap">
        {renderedIcons}
      </pwc-flex>
      <pwc-button
        label="Add Notification"
        variant="primary"
        onPwcClick={addNotification}
      ></pwc-button>
    </pwc-flex>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/icon";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/heading";
import "@progress-i360/progress-web-components/body";

@Component({
  selector: 'icon-demo',
  template: `
    <pwc-flex direction="column" gap="m" padding="m">
      <pwc-heading content="Interactive Icon Demo" size="l"></pwc-heading>
      <pwc-flex align-items="center" gap="m" wrap="wrap">
        <pwc-icon [iconKey]="currentIcon" [size]="iconSize" [color]="iconColor" [clickable]="true" (pwc-click)="handleIconClick()"></pwc-icon>
        <pwc-icon iconKey="loading" [spin]="isLoading" color="info"></pwc-icon>
      </pwc-flex>
      <pwc-flex gap="s" wrap="wrap">
        <pwc-button label="Change Icon" variant="outline" (pwc-click)="changeIcon()"></pwc-button>
        <pwc-button label="Toggle Size" variant="outline" (pwc-click)="toggleSize()"></pwc-button>
        <pwc-button label="Toggle Loading" variant="primary" (pwc-click)="toggleLoading()"></pwc-button>
      </pwc-flex>
      <pwc-body [content]="'Current: ' + currentIcon + ' (' + iconSize + ', ' + iconColor + ')'" color="subtle" size="xs"></pwc-body>
    </pwc-flex>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class IconDemo {
  currentIcon = 'settings';
  iconSize = 'm';
  iconColor = 'normal';
  isLoading = false;
  clickCount = 0;

  icons = ['settings', 'user', 'notification', 'search', 'home'];
  sizes = ['s', 'm', 'l', 'xl'];
  colors = ['normal', 'success', 'danger', 'warning', 'info'];

  handleIconClick() {
    this.clickCount++;
    this.iconColor = this.colors[this.clickCount % this.colors.length];
  }

  changeIcon() {
    const currentIndex = this.icons.indexOf(this.currentIcon);
    this.currentIcon = this.icons[(currentIndex + 1) % this.icons.length];
  }

  toggleSize() {
    const currentIndex = this.sizes.indexOf(this.iconSize);
    this.iconSize = this.sizes[(currentIndex + 1) % this.sizes.length];
  }

  toggleLoading() {
    this.isLoading = !this.isLoading;
  }
}
import '@progress-i360/progress-web-components/icon';

const infoIcon = document.createElement('pwc-icon');
infoIcon.setAttribute('icon-key', 'information');
infoIcon.setAttribute('color', 'info');
infoIcon.setAttribute('size', 'l');
infoIcon.setAttribute('clickable', 'true');

const loader = document.createElement('pwc-icon');
loader.setAttribute('icon-key', 'loading');
loader.setAttribute('spin', 'true');
loader.setAttribute('color', 'subtle');

document.body.appendChild(infoIcon);
document.body.appendChild(loader);

Usage Patterns

  • Status Communication - Use semantic colors (danger, success, warning, info) to convey system states and feedback
  • Interactive Navigation - Implement clickable icons with appropriate hover states for menu items and action buttons
  • Loading Indicators - Apply spin animation to loading icons for visual feedback during data processing
  • Brand Identity - Leverage brand icon type for company logos and proprietary symbol integration

Best Practices

Content Strategy Guidelines

  • Semantic Meaning - Choose icons that have clear, universally understood meanings within your user context
  • Consistent Usage - Use the same icon consistently for the same action or concept throughout the application
  • Color Semantics - Apply color variants that align with their semantic meaning (danger for errors, success for completion)
  • Accessibility Labels - Always provide meaningful titles and ARIA labels for screen reader compatibility

Performance Optimization

  • Icon Caching - Leverage SVG mask loading system for efficient icon rendering and browser caching
  • Size Optimization - Choose appropriate icon sizes to minimize DOM impact while maintaining visual clarity
  • Animation Control - Use spin animation sparingly to avoid overwhelming users or impacting performance
  • Event Management - Implement efficient click event handling with proper event delegation patterns

Integration Architecture

  • Component Composition - Seamlessly integrate with other PWC components through consistent styling tokens
  • Design System Alignment - Utilize Carbon Design System icons for standardized visual language
  • Flexible Positioning - Support flex layout properties for precise positioning within parent containers
  • Dynamic State Management - Enable runtime icon changes through reactive property updates

Common Use Cases

Data Table Headers

  • Sort Indicators - Use directional icons to show column sort states with appropriate color coding
  • Filter Controls - Implement clickable filter icons with hover states for data manipulation
  • Action Buttons - Display edit, delete, and view icons with semantic colors for row-level operations

Search Result Sections

  • Result Type Icons - Categorize search results with type-specific icons (document, user, folder)
  • Status Indicators - Show result relevance or processing states with color-coded status icons
  • Quick Actions - Provide clickable shortcut icons for common result actions like share or bookmark

Dashboard Widget Headers

  • Widget Type Icons - Identify widget functionality with clear, recognizable category icons
  • Status Monitoring - Display real-time status with color-coded icons for system health monitoring
  • Configuration Access - Use settings icons as entry points for widget customization and configuration

Troubleshooting

Common Issues

Icons Not Displaying

Problem: Icon appears as empty space or placeholder

Solution:

  • Verify iconKey matches available icon names and check SVG file path resolution

Color Not Applied

Problem: Icon displays in default color instead of specified variant

Solution:

  • Ensure color property uses valid IconColor enum values and CSS custom properties are loaded

Click Events Not Working

Problem: Clickable icons don't respond to user interaction

Solution:

  • Set clickable property to true and verify event handler is properly bound to pwc-click event

Animation Performance Issues

Problem: Spin animation causes visual lag or performance degradation

Solution:

  • Limit concurrent spinning icons and consider using CSS will-change property for optimization

Implementation Support

For detailed implementation guidance:

  • Carbon Integration - Seamlessly works with Carbon Design System icon library for consistent visual language
  • Brand Customization - Supports custom brand icons with specialized dimensions and positioning controls
  • Event System - Provides standardized click event handling through PWC component event architecture

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.