!!! warning "Pending Review" Pending Review from User Experience (UX)
Focus Component
Overview
The PWC Focus component provides visual focus indication and styling wrapper for form elements and interactive components. Built as a utility component, it enhances accessibility by providing consistent focus outlines and semantic color variants for different states and contexts.
Core Capabilities
- Focus Visualization - Consistent focus ring styling with brand colors and accessibility-compliant contrast ratios
-
Semantic Variants - Six color variants (default, critical, invalid, success, tip, warning) for contextual state indication
-
Flexible Layout - Support for flex properties and alignment options to integrate with various layout patterns
-
Blur Border Option - Additional border styling for enhanced visual separation when elements lose focus
-
CSS Modern Features - Uses :has() selector for advanced styling based on child element focus states
- Accessibility Standards - WCAG-compliant focus indicators that work with keyboard navigation and screen readers
When to use Focus:
- Form elements requiring enhanced focus visibility beyond browser defaults
- Interactive components needing contextual color coding for different states
- Complex form layouts where consistent focus styling improves user experience
- Accessibility-critical interfaces where clear focus indication is essential for navigation
When not to use Focus:
- Simple text links or buttons where browser default focus styling is sufficient
- Non-interactive elements that don't receive keyboard focus
- Components that already include their own focus management and styling
Basic Implementation
import React from 'react';
import { PwcFocus, PwcInput } from "@progress-i360/pwc-react";
function MyComponent() {
return (
<>
<PwcFocus variant="default">
<input
type="text"
placeholder="Enter your name"
style={{ border: 'none', outline: 'none', padding: '8px' }}
/>
</PwcFocus>
<PwcFocus variant="invalid">
<input
type="email"
placeholder="Invalid email format"
style={{ border: 'none', outline: 'none', padding: '8px' }}
/>
</PwcFocus>
<PwcFocus variant="success" flex>
<PwcInput
type="text"
placeholder="Valid input"
name="validInput"
/>
</PwcFocus>
</>
);
}
import '@progress-i360/progress-web-components/focus';
import '@progress-i360/progress-web-components/input';
function FocusStates() {
return (
<>
<pwc-focus variant="success" flex>
<pwc-input
type="text"
name="validated-input"
value="Valid input"
></pwc-input>
</pwc-focus>
<pwc-focus variant="warning" blur-border>
<select style={{ border: 'none', outline: 'none', padding: '8px' }}>
<option value="">Choose option</option>
<option value="high">High priority</option>
<option value="low">Low priority</option>
</select>
</pwc-focus>
</>
);
}
import { Component, CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
import "@progress-i360/progress-web-components/body";
import "@progress-i360/progress-web-components/button";
import "@progress-i360/progress-web-components/flex";
import "@progress-i360/progress-web-components/focus";
import "@progress-i360/progress-web-components/heading";
@Component({
selector: 'focus-demo',
template: `
<pwc-flex direction="column" gap="m" padding="m">
<pwc-heading content="Focus State Demonstration" size="l"></pwc-heading>
<pwc-flex direction="column" gap="s">
<pwc-body content="Click on the inputs below to see focus styling:"></pwc-body>
<pwc-focus variant="default">
<input type="text" placeholder="Default focus style" (focus)="setFocusType('default')" (blur)="clearFocus()">
</pwc-focus>
<pwc-focus [variant]="currentFocusVariant">
<input type="email" placeholder="Validation focus (try invalid email)"
[value]="emailValue"
(input)="updateEmail($event)"
(focus)="setFocusType('validation')"
(blur)="validateEmail()">
</pwc-focus>
<pwc-focus variant="success" *ngIf="showSuccess">
<input type="text" placeholder="Success state" readonly value="Valid input!">
</pwc-focus>
</pwc-flex>
<pwc-flex gap="s">
<pwc-button label="Trigger Success" variant="success" (pwc-click)="showSuccessState()"></pwc-button>
<pwc-button label="Trigger Warning" variant="warning" (pwc-click)="showWarningState()"></pwc-button>
<pwc-button label="Trigger Error" variant="critical" (pwc-click)="showErrorState()"></pwc-button>
</pwc-flex>
<pwc-body [content]="'Current focus: ' + (currentFocus || 'None') + ', Validations: ' + validationCount" color="subtle" size="xs"></pwc-body>
</pwc-flex>
`,
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class FocusDemo {
currentFocus = '';
currentFocusVariant = 'default';
emailValue = '';
showSuccess = false;
validationCount = 0;
setFocusType(type: string) {
this.currentFocus = type;
}
clearFocus() {
this.currentFocus = '';
}
updateEmail(event: any) {
this.emailValue = event.target.value;
}
validateEmail() {
const isValid = this.emailValue.includes('@') && this.emailValue.includes('.');
this.currentFocusVariant = isValid ? 'success' : 'invalid';
this.validationCount++;
}
showSuccessState() {
this.currentFocusVariant = 'success';
this.showSuccess = true;
this.validationCount++;
}
showWarningState() {
this.currentFocusVariant = 'warning';
this.validationCount++;
}
showErrorState() {
this.currentFocusVariant = 'invalid';
this.validationCount++;
}
}
import '@progress-i360/progress-web-components/focus';
const focusWrapper = document.createElement('pwc-focus');
focusWrapper.setAttribute('variant', 'invalid');
const input = document.createElement('input');
input.type = 'email';
input.placeholder = 'Enter email address';
focusWrapper.appendChild(input);
document.body.appendChild(focusWrapper);
Usage Patterns
- Form Validation - Use semantic variants (invalid, success, warning) to provide visual feedback for field validation states
- Interactive Elements - Wrap buttons, inputs, and custom controls with focus styling for consistent keyboard navigation experience
- State Communication - Apply contextual colors (critical, tip) to communicate urgency, importance, or informational context
- Layout Integration - Use flex and alignment properties to integrate focused elements seamlessly with form layouts
Best Practices
Content Strategy Guidelines
- Semantic Color Usage - Choose focus variants that match the semantic meaning of the content and validation state
- Consistent Application - Apply focus styling consistently across similar interactive elements in the same interface
- Clear Visual Hierarchy - Use focus variants to support, not compete with, other visual hierarchy elements
- Accessibility Priority - Ensure focus indicators meet WCAG contrast requirements and are visible to all users
Performance Optimization
- CSS Modern Features - Leverage :has() selector for efficient styling without JavaScript event handlers
- Minimal DOM Impact - Use focus wrapper only when enhanced styling is needed beyond browser defaults
- State-based Rendering - Conditionally apply focus variants based on actual validation or interaction states
- Layout Efficiency - Use flex and alignment properties to reduce layout recalculations
Integration Architecture
- Form System Integration - Coordinate focus variants with form validation states and error handling
- Design Token Usage - Rely on design system color tokens for consistent focus styling across applications
- Accessibility Standards - Ensure focus management works with screen readers and keyboard navigation patterns
- Component Composition - Combine with other form components while maintaining focus behavior
Common Use Cases
Form Validation
- Input field error states with red focus rings for validation failures
- Success confirmation with green focus styling for completed valid fields
- Warning states with orange focus for fields requiring attention but not blocking submission
Interactive Controls
- Button focus enhancement for primary actions and critical operations
- Custom control focus styling for complex widgets like date pickers and dropdown menus
- Navigation element focus for keyboard accessibility in menus and tab interfaces
Status Indication
- Critical alerts with red focus styling for urgent attention requirements
- Informational tips with purple focus for helpful guidance and contextual information
- Progress indicators with semantic focus colors to show completion states
Troubleshooting
Common Issues
Actions Not Triggering
Symptoms: Focus styles don't appear when elements receive keyboard focus
Solutions:
-
Verify child elements can receive focus (tabindex, focusable elements)
-
Check that :has() selector is supported in target browsers
-
Ensure focus styles aren't overridden by other CSS rules with higher specificity
Actions Not Visible
Symptoms: Focus component doesn't render or appears with default styling
Solutions:
-
Confirm renderSlot function returns valid Lit template result
-
Check CSS imports and focus styles are properly loaded
-
Verify variant names match expected FocusVariant types
Layout Issues
Symptoms: Focus wrapper disrupts intended layout or element positioning
Solutions:
-
Use alignSelf property to control focus wrapper alignment within flex containers
-
Apply flex property when focus wrapper should expand to fill available space
-
Check parent container styling doesn't conflict with focus wrapper display properties
Icon Problems
Symptoms: Focus colors don't match design system or appear incorrect
Solutions:
-
Verify design token CSS variables are loaded and available
-
Check color variant mapping matches intended semantic meaning
-
Ensure focus ring contrast meets accessibility requirements for background colors
Implementation Support
- Accessibility Compliance - Focus indicator implementation strategies meeting WCAG guidelines and screen reader compatibility
- Browser Compatibility - Fallback strategies for browsers that don't support modern CSS features like :has() selector
- Design System Integration - Guidance for consistent focus styling patterns across complex application interfaces
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.