UTA DevHub
UI Development/UI Architecture/Foundation Components Guide

Display Components

Visual elements that present information - text, cards, images, and containers for content presentation.

Display Components

Overview

Display components are foundation elements that present information to users without direct interaction. They focus on visual presentation, typography, layout, and content organization while maintaining consistency through design tokens.

Key Principles for Display Components

All display components should:

  • Use design tokens for all visual properties
  • Support responsive sizing and scaling
  • Maintain proper visual hierarchy
  • Ensure content accessibility
  • Handle loading and error states gracefully

Text Component

The Text component is the foundation for all typography in your application. It ensures consistent text rendering across platforms while supporting various typographic styles.

Text Interface

// ui/foundation/Text/types.ts
import type { TextProps as RNTextProps } from 'react-native';
 
export interface TextProps extends RNTextProps {
  /**
   * Typography variant
   * @default 'body'
   */
  variant?: 'heading' | 'subheading' | 'body' | 'caption' | 'label';
  
  /**
   * Size variant
   * @default 'medium'
   */
  size?: 'small' | 'medium' | 'large' | 'xlarge';
  
  /**
   * Text color
   * @default 'primary'
   */
  color?: 'primary' | 'secondary' | 'disabled' | 'error' | 'success' | 'warning' | string;
  
  /**
   * Font weight
   * @default 'normal'
   */
  weight?: 'normal' | 'medium' | 'semibold' | 'bold';
  
  /**
   * Text alignment
   * @default 'left'
   */
  align?: 'left' | 'center' | 'right' | 'justify';
  
  /**
   * Text content
   */
  children: React.ReactNode;
}

Text Implementation

// ui/foundation/Text/Text.tsx
import React from 'react';
import { Text as RNText } from 'react-native';
import { theme } from '@/core/shared/styles/theme';
import { typography } from '@/core/shared/styles/typography';
import type { TextProps } from './types';
 
export const Text: React.FC<TextProps> = ({
  variant = 'body',
  size = 'medium',
  color = 'primary',
  weight = 'normal',
  align = 'left',
  children,
  style,
  ...props
}) => {
  const getVariantStyles = () => {
    switch (variant) {
      case 'heading':
        return {
          fontWeight: typography.weights.bold,
          lineHeight: typography.lineHeights.tight,
        };
      case 'subheading':
        return {
          fontWeight: typography.weights.semibold,
          lineHeight: typography.lineHeights.normal,
        };
      case 'body':
        return {
          fontWeight: typography.weights.normal,
          lineHeight: typography.lineHeights.normal,
        };
      case 'caption':
        return {
          fontWeight: typography.weights.normal,
          lineHeight: typography.lineHeights.normal,
          fontSize: typography.sizes.small,
        };
    }
  };
 
  const getColorValue = () => {
    switch (color) {
      case 'primary':
        return theme.colors.text.primary;
      case 'secondary':
        return theme.colors.text.secondary;
      case 'disabled':
        return theme.colors.text.disabled;
      case 'error':
        return theme.colors.error[500];
      case 'success':
        return theme.colors.success[500];
      case 'warning':
        return theme.colors.warning[500];
      default:
        return typeof color === 'string' ? color : theme.colors.text.primary;
    }
  };
 
  const textStyles = {
    ...getVariantStyles(),
    fontSize: variant === 'caption' ? typography.sizes.small : typography.sizes[size],
    fontWeight: typography.weights[weight],
    color: getColorValue(),
    textAlign: align,
  };
 
  return (
    <RNText 
      style={[textStyles, style]}
      accessibilityRole="text"
      {...props}
    >
      {children}
    </RNText>
  );
};

Card Component

Cards are containers that group related content and actions, providing visual boundaries and consistent spacing.

Card Interface

// ui/foundation/Card/types.ts
import type { ViewProps } from 'react-native';
 
export interface CardProps extends ViewProps {
  /**
   * Visual variant
   * @default 'elevated'
   */
  variant?: 'elevated' | 'outlined' | 'filled';
  
  /**
   * Padding size
   * @default 'medium'
   */
  padding?: 'none' | 'small' | 'medium' | 'large' | number;
  
  /**
   * Card content
   */
  children: React.ReactNode;
}

Card Implementation

// ui/foundation/Card/Card.tsx
import React from 'react';
import { View } from 'react-native';
import { theme } from '@/core/shared/styles/theme';
import { shadows } from '@/core/shared/styles/shadows';
import type { CardProps } from './types';
 
export const Card: React.FC<CardProps> = ({
  variant = 'elevated',
  padding = 'medium',
  children,
  style,
  ...props
}) => {
  const getVariantStyles = () => {
    switch (variant) {
      case 'elevated':
        return {
          backgroundColor: theme.colors.surface,
          ...shadows.medium,
        };
      case 'outlined':
        return {
          backgroundColor: theme.colors.surface,
          borderWidth: 1,
          borderColor: theme.colors.border.default,
        };
      case 'filled':
        return {
          backgroundColor: theme.colors.surface.secondary,
        };
    }
  };
 
  const getPaddingValue = () => {
    switch (padding) {
      case 'none':
        return 0;
      case 'small':
        return theme.spacing.sm;
      case 'medium':
        return theme.spacing.md;
      case 'large':
        return theme.spacing.lg;
      default:
        return typeof padding === 'number' ? padding : theme.spacing.md;
    }
  };
 
  const cardStyles = {
    ...getVariantStyles(),
    borderRadius: theme.radii.lg,
    padding: getPaddingValue(),
  };
 
  return (
    <View 
      style={[cardStyles, style]}
      {...props}
    >
      {children}
    </View>
  );
};

Image Component

The Image component extends React Native's Image with consistent sizing, loading states, and accessibility features.

Image Interface

export interface ImageProps extends RNImageProps {
  /**
   * Image dimensions preset
   * @default 'medium'
   */
  size?: 'small' | 'medium' | 'large' | 'full' | { width: number; height: number };
  
  /**
   * Border radius variant
   * @default 'none'
   */
  rounded?: 'none' | 'small' | 'medium' | 'large' | 'full';
  
  /**
   * Aspect ratio
   */
  aspectRatio?: number;
  
  /**
   * Fallback component for loading/error
   */
  fallback?: React.ReactNode;
  
  /**
   * Alt text for accessibility
   */
  alt: string;
}

Image Best Practices

  • Always provide meaningful alt text
  • Use consistent sizing presets
  • Handle loading and error states
  • Optimize image sizes for performance
  • Consider lazy loading for lists
  • Test on various screen densities

Icon Component

Icons are essential for visual communication and UI enhancement.

Icon Interface

export interface IconProps {
  /**
   * Icon name from the icon set
   */
  name: string;
  
  /**
   * Icon size
   * @default 24
   */
  size?: number | 'small' | 'medium' | 'large';
  
  /**
   * Icon color
   * @default theme.colors.text.primary
   */
  color?: string;
  
  /**
   * Accessibility label
   */
  accessibilityLabel?: string;
}

Icon Usage Guidelines

  • Use semantic names for icons
  • Maintain consistent sizing
  • Ensure sufficient contrast
  • Provide labels for standalone icons
  • Group related icons visually
  • Consider platform-specific icons

Badge Component

Badges display small amounts of information, typically numbers or status indicators.

Badge Interface

export interface BadgeProps {
  /**
   * Badge content
   */
  children: React.ReactNode;
  
  /**
   * Visual variant
   * @default 'default'
   */
  variant?: 'default' | 'primary' | 'success' | 'warning' | 'error';
  
  /**
   * Size variant
   * @default 'medium'
   */
  size?: 'small' | 'medium' | 'large';
  
  /**
   * Dot indicator only
   * @default false
   */
  dot?: boolean;
}

Avatar Component

Avatars represent users or entities with images or initials.

Avatar Interface

export interface AvatarProps {
  /**
   * Image source
   */
  source?: ImageSourcePropType;
  
  /**
   * Fallback text (initials)
   */
  name?: string;
  
  /**
   * Size variant
   * @default 'medium'
   */
  size?: 'small' | 'medium' | 'large' | 'xlarge' | number;
  
  /**
   * Shape variant
   * @default 'circle'
   */
  shape?: 'circle' | 'square';
  
  /**
   * Online status indicator
   */
  status?: 'online' | 'offline' | 'away' | 'busy';
}

General Best Practices for Display Components

Performance Optimization

  • Use React.memo for components with stable props
  • Implement lazy loading for images in lists
  • Optimize image assets before bundling
  • Cache computed styles with StyleSheet.create
  • Minimize re-renders with proper prop design

Accessibility Considerations

  • Provide alternative text for all images
  • Ensure text has sufficient contrast
  • Support Dynamic Type scaling
  • Include proper semantic markup
  • Test with screen readers

Testing Display Components

describe('Display Component Tests', () => {
  it('renders with correct styles', () => {
    const { getByText } = render(
      <Text variant="heading" color="primary">
        Test Heading
      </Text>
    );
    
    const text = getByText('Test Heading');
    expect(text.props.style).toMatchObject({
      fontSize: typography.sizes.large,
      color: theme.colors.text.primary,
    });
  });
  
  it('applies design tokens correctly', () => {
    const { getByTestId } = render(
      <Card variant="elevated" testID="test-card">
        <Text>Content</Text>
      </Card>
    );
    
    const card = getByTestId('test-card');
    expect(card.props.style).toMatchObject({
      backgroundColor: theme.colors.surface,
      borderRadius: theme.radii.lg,
    });
  });
});

Summary

Display components are the visual building blocks of your application. They should:

  • Be Consistent: Use design tokens exclusively
  • Be Flexible: Support common variations and patterns
  • Be Accessible: Include proper semantics and alternatives
  • Be Performant: Optimize for smooth rendering
  • Be Testable: Enable easy visual regression testing

Next Steps