Platform-Aware Keyboard Shortcuts
Building Platform-Aware Keyboard Shortcuts: A Cross-Platform UX Enhancement
Internal Development Case Study
The Problem
While working on the portfolio's search functionality, we discovered a subtle but important UX inconsistency: all keyboard shortcut displays showed the macOS Command symbol (⌘) regardless of the user's operating system. Windows and Linux users were seeing ⌘F when they should see Ctrl+F, creating confusion and breaking platform conventions.
This might seem like a minor detail, but these small inconsistencies compound to create a less polished user experience. Users expect applications to respect their platform's conventions.
The Investigation
During a search overlay review, we identified multiple locations where keyboard shortcuts were hardcoded:
- Internship search overlay:
⌘Fand⌘⇧C - New grad search overlay: Same shortcuts
- Hackathon search overlay: Same shortcuts
- Page-level search buttons: Hardcoded
⌘Fin kbd elements
Each location had duplicate logic for displaying shortcuts, and none detected the user's platform.
The Solution: A Platform-Aware System
Rather than fixing each location individually, we built a reusable system that automatically adapts to the user's platform.
Core Architecture
Platform Detection
export function isMac(): boolean {
return typeof navigator !== 'undefined' &&
navigator.platform.toUpperCase().indexOf('MAC') >= 0;
}Unified Component Interface
interface KeyboardShortcutProps {
keys: string; // e.g., "cmd+f", "shift+c", "enter"
className?: string;
}Smart Key Mapping
The system translates logical keys to platform-appropriate symbols:
| Input Key | macOS Output | Windows/Linux Output |
|---|---|---|
cmd+f | ⌘F (with icon) | Ctrl+F |
cmd+shift+c | ⌘⇧C | Ctrl+Shift+C |
alt+tab | ⌥⇥ | Alt+Tab |
Rendering Strategy
For Mac users seeing cmd+f, we maintain the visual design with the Command icon:
<div className="flex items-center gap-1">
<Command className="h-3 w-3" />
<span>F</span>
</div>For other platforms, we render clean text in a kbd element:
<kbd className="rounded border px-1.5 py-0.5">Ctrl+F</kbd>Implementation Challenges
SSR Compatibility
Since we're using Next.js, we needed to handle server-side rendering where navigator isn't available:
// Safe platform detection that works during SSR
const isMac = typeof navigator !== 'undefined' &&
navigator.platform.toUpperCase().indexOf('MAC') >= 0;Tailwind Integration
The existing design system used consistent kbd styling across components. Our solution maintains this by applying the same classes programmatically:
<kbd className="rounded border border-kbd-border bg-kbd-background px-1.5 py-0.5 text-kbd-foreground text-xs">
{formattedKeys}
</kbd>Design System Consistency
The Command icon has specific visual treatment in the design. We preserved this for Mac users while ensuring Windows/Linux users get equally polished text-based shortcuts.
Code Elimination
The refactor eliminated significant code duplication across 6 components:
Before:
// Repeated in every component
const isMac = navigator.platform.indexOf('Mac') >= 0;
{isMac ? (
<>
<Command className="h-3 w-3" />
<span>F</span>
</>
) : (
<span>Ctrl+F</span>
)}After:
// Single line in every component
<KeyboardShortcut keys="cmd+f" />Technical Outcomes
Performance
- Reduced bundle size by eliminating duplicate platform detection logic
- Consistent platform detection across all components
- Single source of truth for keyboard shortcut rendering
Developer Experience
- New keyboard shortcuts can be added with a single component
- Platform handling is automatic and consistent
- Type-safe key combinations with clear string format
User Experience
- Mac users see familiar ⌘ symbols with proper iconography
- Windows/Linux users see standard Ctrl+ notation
- All platforms get appropriately styled shortcuts that match the design system
Future Enhancements
This foundation enables several future improvements:
- Tooltip Integration: Hover states could show additional context
- Accessibility: Screen readers could announce platform-appropriate shortcuts
- Customization: Users could potentially choose their preferred notation style
- Documentation: Automatically generate platform-specific help docs
Lessons Learned
Start With Abstractions
Rather than fixing the immediate problem in each location, building the reusable system saved time and prevents future inconsistencies.
Small Details Matter
Platform conventions seem minor but significantly impact perceived polish and professionalism.
TypeScript Pays Off
Strong typing caught several edge cases during implementation and makes the API self-documenting for future developers.
This is one of those win-win situations that actually lives up to the hype. Users get the experience that just feels right, and your codebase stays organized instead of turning into spaghetti.