Skip to content

Pending Review

Pending Review from User Experience (UX)

Body Component

Overview

The PWC Body is a fundamental typography component in the Progress Web Components design system. It provides consistent body text styling with flexible size, color, and weight options for readable content display across React and Angular applications.

Core Capabilities

  • Typography Hierarchy - XS and S sizes following design system text scale
  • Weight Variations - Regular, semi-bold, and bold font weights for content emphasis
  • Color System - 26 color variants including base, subtle, accent, and semantic colors
  • Content Integration - Flexible content property with slot support for complex markup
  • Design Token Integration - Uses system font family and consistent line height values
  • Accessibility Support - Optimal line length with 100ch max-width and proper contrast ratios

When to use Body:

  • Display paragraph text, descriptions, and content blocks
  • Show form labels, help text, and instructional content
  • Present data values and informational text in tables and lists
  • Create consistent text hierarchy within interface components

When not to use Body:

  • Page or section headings (use Heading component instead)
  • Interactive text elements (use Link component for clickable text)
  • Large blocks of content requiring advanced formatting

Basic Implementation

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

function ContentDisplay() {
  const [messageType, setMessageType] = useState('info');
  const [isHighlighted, setIsHighlighted] = useState(false);

  // React 18: Manual memoization with useMemo
  const messageConfig = useMemo(() => {
    const configs = {
      info: { color: 'blue-base', content: 'Information: Process completed successfully' },
      warning: { color: 'orange-base', content: 'Warning: Please review your settings' },
      error: { color: 'red-base', content: 'Error: Something went wrong' },
      success: { color: 'green-base', content: 'Success: Changes saved successfully' }
    };
    return configs[messageType] || configs.info;
  }, [messageType]);

  // React 18: useCallback for event handlers
  const cycleMessageType = useCallback(() => {
    const types = ['info', 'warning', 'error', 'success'];
    const currentIndex = types.indexOf(messageType);
    setMessageType(types[(currentIndex + 1) % types.length]);
  }, [messageType]);

  const toggleHighlight = useCallback(() => {
    setIsHighlighted(prev => !prev);
  }, []);

  return (
      <PwcFlex direction="column" gap="m">
        <PwcBody 
          content={messageConfig.content}
          color={messageConfig.color}
          weight={isHighlighted ? 'semi-bold' : 'regular'}
        />
        <PwcFlex gap="s">
          <PwcButton
            label="Change Message"
            variant="primary"
            onPwcClick={cycleMessageType}
          />
          <PwcButton
            label={`${isHighlighted ? 'Remove' : 'Add'} Emphasis`}
            variant="outline"
            onPwcClick={toggleHighlight}
          />
        </PwcFlex>
        <PwcBody 
          content={`Current: ${messageType} message`}
          size="xs" 
          color="subtle"
        />
      </PwcFlex>
  );
}
import { useState, useDeferredValue, useOptimistic, useActionState } from 'react';
import '@progress-i360/progress-web-components/body';
import '@progress-i360/progress-web-components/flex';
import '@progress-i360/progress-web-components/button';

function DynamicContentDisplay() {
  const [notifications, setNotifications] = useState([
    { id: 1, text: 'Welcome to the application', priority: 'low' },
    { id: 2, text: 'New message received', priority: 'medium' }
  ]);

  // React 19+: Defer expensive notification rendering
  const deferredNotifications = useDeferredValue(notifications);

  // React 19+: Optimistic updates for instant feedback
  const [optimisticNotifications, addOptimisticNotification] = useOptimistic(
    deferredNotifications,
    (state, newNotification) => [newNotification, ...state]
  );

  // React 19+: useActionState for form-like interactions
  const [actionState, submitAction, isPending] = useActionState(
    async (prevState, formData) => {
      const text = formData.get('notification');
      const priority = Math.random() > 0.5 ? 'high' : 'medium';

      const newNotification = {
        id: Date.now(),
        text: text || `Auto-generated notification ${Date.now()}`,
        priority
      };

      addOptimisticNotification(newNotification);

      // Simulate API call
      await new Promise((resolve) => setTimeout(resolve, 1000));
      setNotifications((prev) => [newNotification, ...prev]);

      return { success: true, count: prevState.count + 1 };
    },
    { success: false, count: 0 }
  );

  const getColorByPriority = (priority: string) => {
    switch (priority) {
      case 'high':
        return 'red-base';
      case 'medium':
        return 'orange-base';
      case 'low':
        return 'blue-base';
      default:
        return 'base';
    }
  };

  return (
    <pwc-flex direction="column" gap="m">
      <pwc-body content="Notification Center" weight="bold"></pwc-body>

      <pwc-flex direction="column" gap="s">
        {optimisticNotifications.map((notification) => (
          <pwc-body
            key={notification.id}
            content={notification.text}
            color={getColorByPriority(notification.priority)}
            size="s"
          ></pwc-body>
        ))}
      </pwc-flex>

      <form action={submitAction}>
        <pwc-flex gap="s" align-items="center">
          <pwc-button
            type="submit"
            label={isPending ? 'Adding...' : 'Add Notification'}
            variant="primary"
            disabled={isPending}
          ></pwc-button>
          <pwc-body
            content={`Total notifications: ${actionState.count + optimisticNotifications.length}`}
            size="xs"
            color="subtle"
          ></pwc-body>
        </pwc-flex>
      </form>
    </pwc-flex>
  );
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/body";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/heading";

@Component({
  selector: 'body-demo',
  template: `
    <pwc-flex direction="column" gap="m" padding="m">
      <pwc-heading content="Body Text Styles" size="l"></pwc-heading>
      <pwc-body [content]="bodyText" [size]="textSize" [weight]="textWeight"></pwc-body>
      <pwc-flex gap="s">
        <pwc-button label="Toggle Size" variant="outline" (pwc-click)="toggleSize()"></pwc-button>
        <pwc-button label="Toggle Weight" variant="outline" (pwc-click)="toggleWeight()"></pwc-button>
        <pwc-button label="Update Text" variant="primary" (pwc-click)="updateText()"></pwc-button>
      </pwc-flex>
      <pwc-body [content]="'Current: Size ' + textSize + ', Weight ' + textWeight" color="subtle" size="xs"></pwc-body>
    </pwc-flex>
  `,
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class BodyDemo {
  bodyText = 'This is sample body text that demonstrates different styling options.';
  textSize = 's';
  textWeight = 'regular';
  textCount = 0;

  toggleSize() {
    this.textSize = this.textSize === 's' ? 'xs' : 's';
  }

  toggleWeight() {
    const weights = ['regular', 'semi-bold', 'bold'];
    const currentIndex = weights.indexOf(this.textWeight);
    this.textWeight = weights[(currentIndex + 1) % weights.length];
  }

  updateText() {
    this.textCount++;
    this.bodyText = `Updated body text example #${this.textCount}. This demonstrates dynamic content changes.`;
  }
}
// Import the component
import '@progress-i360/progress-web-components/body';

// Create body text elements
const bodyText = document.createElement('pwc-body');
bodyText.setAttribute('content', 'Main content text');
bodyText.setAttribute('size', 's');
bodyText.setAttribute('color', 'base');

const secondaryText = document.createElement('pwc-body');
secondaryText.setAttribute('content', 'Secondary information');
secondaryText.setAttribute('size', 'xs');
secondaryText.setAttribute('color', 'subtle');
secondaryText.setAttribute('weight', 'semi-bold');

// Append to DOM
document.querySelector('#content-area').appendChild(bodyText);
document.querySelector('#content-area').appendChild(secondaryText);

Usage Patterns

Body components adapt to different content and styling scenarios:

  • Standard Content - Default size and base color for primary text content
  • Secondary Information - XS size with subtle color for metadata and helper text
  • Emphasis Text - Semi-bold or bold weight for important information highlighting
  • Semantic Colors - Accent colors for status messages, warnings, and categorized content

Best Practices

Content Strategy Guidelines

  • Clear Hierarchy - Use size and weight combinations to establish clear content hierarchy
  • Consistent Coloring - Apply semantic colors consistently across similar content types
  • Readable Line Length - Leverage 100ch max-width for optimal reading experience
  • Content Appropriateness - Match text styling to content purpose and importance level

Performance Optimization

  • Efficient Rendering - Minimize unnecessary re-renders for static text content
  • Token Usage - Leverage design system tokens for consistent performance
  • Bundle Optimization - Import only required typography components
  • Font Loading - Ensure proper Source Sans Pro font loading strategies

Integration Architecture

  • Component Composition - Integrate seamlessly with other typography components
  • Slot Support - Use content property for simple text, slots for complex markup
  • Responsive Behavior - Maintain readability across all screen sizes and devices
  • Theme Compatibility - Work effectively with light and dark theme variations

Common Use Cases

Data Table Headers

  • Column Headers - Use semi-bold weight body text for table column labels
  • Cell Content - Standard body text for data values and descriptive content
  • Table Metadata - XS size with subtle color for row counts and table information

Search Result Sections

  • Result Descriptions - Standard body text for search result snippets and descriptions
  • Metadata Display - XS size body text for dates, categories, and result context
  • Status Information - Semantic colors for result status and relevance indicators

Dashboard Widget Headers

  • Widget Content - Body text for data values, descriptions, and informational content
  • Help Text - Subtle colored body text for widget explanations and guidance
  • Dynamic Content - Various color variants for real-time data and status updates

Troubleshooting

Common Issues

Text Not Displaying

Problem: Body component appears empty or doesn't show content

Solution:

  • Verify content property is set correctly and contains valid string data

Font Not Loading

Problem: Text displays with fallback fonts instead of Source Sans Pro

Solution:

  • Check font loading configuration and ensure design system fonts are available

Color Not Applying

Problem: Text color doesn't match expected color variant

Solution:

  • Verify color property matches available color options and theme is properly configured

Layout Issues

Problem: Text doesn't align properly with other components

Solution:

  • Check CSS integration and ensure proper flexbox properties are applied

Implementation Support

For detailed implementation guidance:

  • Typography Integration - Works seamlessly with other PWC typography components
  • Design System Tokens - Uses standardized font, color, and spacing tokens
  • Framework Compatibility - Tested across React, Angular, and vanilla JavaScript implementations

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.