design-harden
Improve interface resilience through better error handling, i18n support, text overflow handling, and edge case management. Makes interfaces robust and production-ready. Use when asked to harden, make production-ready, handle edge cases, add error states, or fix overflow and i18n issues.
Strengthen interfaces against edge cases, errors, internationalization issues, and real-world usage scenarios that break idealized designs.
Assess Hardening Needs
Identify weaknesses and edge cases:
-
Test with extreme inputs:
- Very long text (names, descriptions, titles)
- Very short text (empty, single character)
- Special characters (emoji, RTL text, accents)
- Large numbers (millions, billions)
- Many items (1000+ list items, 50+ options)
- No data (empty states)
-
Test error scenarios:
- Network failures (offline, slow, timeout)
- API errors (400, 401, 403, 404, 500)
- Validation errors
- Permission errors
- Rate limiting
- Concurrent operations
-
Test internationalization:
- Long translations (German is often 30% longer than English)
- RTL languages (Arabic, Hebrew)
- Character sets (Chinese, Japanese, Korean, emoji)
- Date/time formats
- Number formats (1,000 vs 1.000)
- Currency symbols
Designs that only work with perfect data are not production-ready. Harden against reality.
Reference file (read when assessing accessibility resilience):
references/accessibility.md— WCAG 2.1 AA essentials, ARIA patterns, contrast requirements
Hardening Dimensions
Systematically improve resilience:
Text Overflow and Wrapping
Long text handling:
/* Single line with ellipsis */
.truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* Multi-line with clamp */
.line-clamp {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Allow wrapping */
.wrap {
word-wrap: break-word;
overflow-wrap: break-word;
hyphens: auto;
}
Flex/Grid overflow:
/* Prevent flex items from overflowing */
.flex-item {
min-width: 0; /* Allow shrinking below content size */
overflow: hidden;
}
/* Prevent grid items from overflowing */
.grid-item {
min-width: 0;
min-height: 0;
}
Responsive text sizing:
- Use
clamp()for fluid typography - Set minimum readable sizes (14px on mobile)
- Test text scaling (zoom to 200%)
- Ensure containers expand with text
Internationalization (i18n)
Text expansion:
- Add 30-40% space budget for translations
- Use flexbox/grid that adapts to content
- Test with longest language (usually German)
- Avoid fixed widths on text containers
// Bad: Assumes short English text
<button className="w-24">Submit</button>
// Good: Adapts to content
<button className="px-4 py-2">Submit</button>
RTL (Right-to-Left) support:
/* Use logical properties */
margin-inline-start: 1rem; /* Not margin-left */
padding-inline: 1rem; /* Not padding-left/right */
border-inline-end: 1px solid; /* Not border-right */
/* Or use dir attribute */
[dir="rtl"] .arrow { transform: scaleX(-1); }
Character set support:
- Use UTF-8 encoding everywhere
- Test with CJK characters
- Test with emoji (they can be 2-4 bytes)
- Handle different scripts (Latin, Cyrillic, Arabic)
Date/Time formatting:
// Use Intl API for proper formatting
new Intl.DateTimeFormat('en-US').format(date);
new Intl.DateTimeFormat('de-DE').format(date);
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1234.56);
Pluralization:
// Bad: Assumes English pluralization
`${count} item${count !== 1 ? 's' : ''}`
// Good: Use proper i18n library
t('items', { count }) // Handles complex plural rules
Error Handling
Network errors:
- Show clear error messages
- Provide retry button
- Explain what happened
- Offer offline mode if applicable
- Handle timeout scenarios
{error && (
<ErrorMessage>
<p>Failed to load data. {error.message}</p>
<button onClick={retry}>Try again</button>
</ErrorMessage>
)}
Form validation errors:
- Inline errors near fields
- Clear, specific messages
- Suggest corrections
- Do not block submission unnecessarily
- Preserve user input on error
API errors:
- 400: Show validation errors
- 401: Redirect to login
- 403: Show permission error
- 404: Show not found state
- 429: Show rate limit message
- 500: Show generic error, offer support
Graceful degradation:
- Core functionality works without JavaScript
- Images have alt text
- Progressive enhancement
- Fallbacks for unsupported features
Edge Cases and Boundary Conditions
Empty states: No items, no search results, no data. Provide clear next action.
Loading states: Initial load, pagination, refresh. Show what is loading and time estimates for long operations.
Large datasets: Pagination or virtual scrolling. Search/filter capabilities. Do not load all 10,000 items at once.
Concurrent operations: Prevent double-submission (disable button while loading). Handle race conditions. Optimistic updates with rollback.
Permission states: No permission to view/edit. Read-only mode. Clear explanation of why.
Browser compatibility: Polyfills for modern features. Fallbacks for unsupported CSS. Feature detection, not browser detection.
Input Validation and Sanitization
Client-side validation: Required fields, format validation, length limits, pattern matching, custom rules.
Server-side validation (always): Never trust client-side only. Validate and sanitize all inputs. Protect against injection. Rate limiting.
<input
type="text"
maxlength="100"
pattern="[A-Za-z0-9]+"
required
aria-describedby="username-hint"
/>
<small id="username-hint">
Letters and numbers only, up to 100 characters
</small>
Accessibility Resilience
Keyboard navigation: All functionality accessible via keyboard. Logical tab order. Focus management in modals. Skip links.
Screen reader support: Proper ARIA labels. Announce dynamic changes (live regions). Descriptive alt text. Semantic HTML.
Motion sensitivity:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
High contrast mode: Test in Windows high contrast mode. Do not rely only on color. Provide alternative visual cues.
Performance Resilience
Slow connections: Progressive image loading, skeleton screens, optimistic UI, offline support.
Memory leaks: Clean up event listeners, cancel subscriptions, clear timers, abort pending requests on unmount.
Throttling and debouncing:
const debouncedSearch = debounce(handleSearch, 300);
const throttledScroll = throttle(handleScroll, 100);
Testing Strategies
Manual testing: Test with extreme data, different languages, offline, slow connection (throttle to 3G), screen reader, keyboard-only, old browsers.
Automated testing: Unit tests for edge cases, integration tests for error scenarios, E2E for critical paths, visual regression, accessibility tests (axe, WAVE).
Verify Hardening
Test thoroughly with edge cases:
- Long text: Names with 100+ characters
- Emoji: Emoji in all text fields
- RTL: Arabic or Hebrew
- CJK: Chinese/Japanese/Korean
- Network issues: Disable internet, throttle connection
- Large datasets: 1000+ items
- Concurrent actions: Click submit 10 times rapidly
- Errors: Force API errors, test all error states
- Empty: Remove all data, test empty states
NEVER:
- Assume perfect input
- Ignore internationalization
- Leave error messages generic (“Error occurred”)
- Forget offline scenarios
- Trust client-side validation alone
- Use fixed widths for text
- Assume English-length text
- Block entire interface when one component errors