Harden | Skills Pool
Harden Make interfaces production-ready: error handling, empty states, onboarding flows, i18n, text overflow, and edge case management. Use when the user asks to harden, make production-ready, handle edge cases, add error states, design empty states, improve onboarding, or fix overflow and i18n issues.
pbakaus 20,430 stars Apr 10, 2026 Occupation Categories Architecture Patterns 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)
npx skills add pbakaus/impeccable
stars 20,430
Updated Apr 10, 2026
Occupation
Date/time formats
Number formats (1,000 vs 1.000)
Currency symbols CRITICAL : Designs that only work with perfect data aren't production-ready. Harden against reality.
Hardening Dimensions Systematically improve resilience:
Text Overflow & Wrapping /* 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;
}
/* 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;
}
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)
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); }
Use UTF-8 encoding everywhere
Test with Chinese/Japanese/Korean (CJK) characters
Test with emoji (they can be 2-4 bytes)
Handle different scripts (Latin, Cyrillic, Arabic, etc.)
// ✅ Use Intl API for proper formatting
new Intl.DateTimeFormat('en-US').format(date); // 1/15/2024
new Intl.DateTimeFormat('de-DE').format(date); // 15.1.2024
new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD'
}).format(1234.56); // $1,234.56
// ❌ Bad: Assumes English pluralization
`${count} item${count !== 1 ? 's' : ''}`
// ✅ Good: Use proper i18n library
t('items', { count }) // Handles complex plural rules
Error Handling
Show clear error messages
Provide retry button
Explain what happened
Offer offline mode (if applicable)
Handle timeout scenarios
// Error states with recovery
{error && (
<ErrorMessage>
<p>Failed to load data. {error.message}</p>
<button onClick={retry}>Try again</button>
</ErrorMessage>
)}
Inline errors near fields
Clear, specific messages
Suggest corrections
Don't block submission unnecessarily
Preserve user input on error
Handle each status code appropriately
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
Core functionality works without JavaScript
Images have alt text
Progressive enhancement
Fallbacks for unsupported features
Edge Cases & Boundary Conditions
No items in list
No search results
No notifications
No data to display
Provide clear next action
Initial load
Pagination load
Refresh
Show what's loading ("Loading your projects...")
Time estimates for long operations
Pagination or virtual scrolling
Search/filter capabilities
Performance optimization
Don't load all 10,000 items at once
Prevent double-submission (disable button while loading)
Handle race conditions
Optimistic updates with rollback
Conflict resolution
No permission to view
No permission to edit
Read-only mode
Clear explanation of why
Polyfills for modern features
Fallbacks for unsupported CSS
Feature detection (not browser detection)
Test in target browsers
Onboarding & First-Run Experience Production-ready features work for first-time users, not just power users. Design the paths that get new users to value:
Empty states : Every zero-data screen needs:
What will appear here (description or illustration)
Why it matters to the user
Clear CTA to create the first item or start from a template
Visual interest (not just blank space with "No items yet")
Empty state types to handle:
First use : emphasize value, provide templates
User cleared : light touch, easy to recreate
No results : suggest a different query, offer to clear filters
No permissions : explain why, how to get access
First-run experience : Get users to their "aha moment" as quickly as possible.
Show, don't tell -- working examples over descriptions
Progressive disclosure -- teach one thing at a time, not everything upfront
Make onboarding optional -- let experienced users skip
Provide smart defaults so required setup is minimal
Feature discovery : Teach features when users need them, not upfront.
Contextual tooltips at point of use (brief, dismissable, one-time)
Badges or indicators on new or unused features
Celebrate activation events quietly (a toast, not a modal)
Force long onboarding before users can touch the product
Show the same tooltip repeatedly (track and respect dismissals)
Block the entire UI during a guided tour
Create separate tutorial modes disconnected from the real product
Design empty states that just say "No items" with no next action
Required fields
Format validation (email, phone, URL)
Length limits
Pattern matching
Custom validation rules
Server-side validation (always):
Never trust client-side only
Validate and sanitize all inputs
Protect against injection attacks
Rate limiting
<!-- Set clear constraints -->
<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
All functionality accessible via keyboard
Logical tab order
Focus management in modals
Skip links for long content
Proper ARIA labels
Announce dynamic changes (live regions)
Descriptive alt text
Semantic HTML
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Test in Windows high contrast mode
Don't rely only on color
Provide alternative visual cues
Progressive image loading
Skeleton screens
Optimistic UI updates
Offline support (service workers)
Clean up event listeners
Cancel subscriptions
Clear timers/intervals
Abort pending requests on unmount
// Debounce search input
const debouncedSearch = debounce(handleSearch, 300);
// Throttle scroll handler
const throttledScroll = throttle(handleScroll, 100);
Testing Strategies
Test with extreme data (very long, very short, empty)
Test in different languages
Test offline
Test slow connection (throttle to 3G)
Test with screen reader
Test keyboard-only navigation
Test on old browsers
Unit tests for edge cases
Integration tests for error scenarios
E2E tests for critical paths
Visual regression tests
Accessibility tests (axe, WAVE)
IMPORTANT : Hardening is about expecting the unexpected. Real users will do things you never imagined.
Assume perfect input (validate everything)
Ignore internationalization (design for global)
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
Verify Hardening Test thoroughly with edge cases:
Long text : Try names with 100+ characters
Emoji : Use emoji in all text fields
RTL : Test with Arabic or Hebrew
CJK : Test with Chinese/Japanese/Korean
Network issues : Disable internet, throttle connection
Large datasets : Test with 1000+ items
Concurrent actions : Click submit 10 times rapidly
Errors : Force API errors, test all error states
Empty : Remove all data, test empty states
Remember: You're hardening for production reality, not demo perfection. Expect users to input weird data, lose connection mid-flow, and use your product in unexpected ways. Build resilience into every component.
02
Hardening Dimensions