بنقرة واحدة
applying-behavior
Touch, keyboard, and form interaction patterns for accessible UI
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Touch, keyboard, and form interaction patterns for accessible UI
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
Creative direction for AI image generation — distill a codebase's FEEL canon (taste tokens, TDRs, persona files) into prompt-ready material vocabulary, map product architecture to scene systems, and enforce visual discipline across banner sets and scene stacks.
Analyze feedback logs to detect design preference patterns. Auto-contributes HIGH confidence patterns upstream.
Motion design and animation patterns for UI based on Emil Kowalski's principles
Design physics system for UI interactions - sync strategies, timing, confirmations
Convert vague "feel" feedback into specific actionable fixes via decomposition questions
Component design patterns - compound components, composition, props API
| name | applying-behavior |
| description | Touch, keyboard, and form interaction patterns for accessible UI |
| user-invocable | true |
| allowed-tools | Read, Write, Glob, Grep, Edit |
Touch device considerations, keyboard navigation, form patterns, and accessibility fundamentals for interactive UI.
/behavior
This skill provides guidance on making interfaces work well across input methods and devices. Use it when:
Disable hover effects on touch devices. Touch triggers hover on tap, causing false positives:
/* Only apply hover on devices that support it */
@media (hover: hover) and (pointer: fine) {
.element:hover {
transform: scale(1.05);
}
}
Important: Don't rely on hover effects for UI to work. Hover should enhance, not enable functionality.
Ensure minimum 44px tap targets on all interactive elements:
.icon-button {
/* Visual size can be smaller */
width: 24px;
height: 24px;
position: relative;
}
/* But hit area should be 44px */
.icon-button::before {
content: '';
position: absolute;
inset: -10px;
}
Or use minimum dimensions:
.small-button {
min-width: 44px;
min-height: 44px;
display: flex;
align-items: center;
justify-content: center;
}
For custom gestures, disable native behavior:
/* Disable all touch behaviors for custom canvas */
.custom-canvas {
touch-action: none;
}
/* Prevent double-tap zoom on controls */
button, a, input {
touch-action: manipulation;
}
Apply muted and playsinline for autoplay without fullscreen:
<video autoplay muted playsinline loop>
<source src="video.mp4" type="video/mp4" />
</video>
Show correct modifier key based on OS:
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
const modKey = isMac ? 'Cmd' : 'Ctrl';
// Display: "Save (Cmd+S)" on Mac, "Save (Ctrl+S)" on Windows
Ensure consistent tabbing through visible elements only:
/* Hide from tab order when not visible */
.hidden-panel {
visibility: hidden;
}
/* Or use inert attribute */
<div inert={!isVisible}>...</div>
Ensure focused elements are visible:
function handleFocus(e) {
e.target.scrollIntoView({
behavior: 'smooth',
block: 'nearest',
});
}
When opening modals:
function Modal({ isOpen, onClose, triggerRef }) {
const modalRef = useRef();
useEffect(() => {
if (isOpen) {
modalRef.current?.focus();
} else {
triggerRef.current?.focus();
}
}, [isOpen]);
return (
<div ref={modalRef} tabIndex={-1} role="dialog">
{/* Modal content */}
</div>
);
}
Always associate labels with inputs:
<label for="email">Email</label>
<input id="email" type="email" />
<!-- Or wrap the input -->
<label>
Email
<input type="email" />
</label>
Use appropriate types for mobile keyboards:
<input type="email" /> <!-- Email keyboard -->
<input type="tel" /> <!-- Phone keypad -->
<input type="url" /> <!-- URL keyboard -->
<input type="number" /> <!-- Numeric keypad -->
<input type="search" /> <!-- Search with clear -->
Ensure 16px minimum to prevent zoom on focus:
input, textarea, select {
font-size: 16px;
}
Position icons absolutely, not as siblings:
.input-wrapper {
position: relative;
}
.input-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
}
.input-field {
padding-left: 40px;
}
Don't autofocus on touch devices:
const isTouchDevice = 'ontouchstart' in window;
<input autoFocus={!isTouchDevice} />
Wrap inputs with <form> for Enter key submission:
<form onSubmit={handleSubmit}>
<input type="text" />
<button type="submit">Submit</button>
</form>
Support Cmd/Ctrl+Enter for textareas:
function handleKeyDown(e) {
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
handleSubmit();
}
}
Disable password managers when not needed:
<input
data-lpignore="true"
data-1p-ignore
spellcheck="false"
autocomplete="off"
/>
Always set labels on icon buttons:
<button aria-label="Close dialog">
<CloseIcon />
</button>
<button aria-label="Search">
<SearchIcon />
</button>
Decorative code-built illustrations need ARIA:
<div
role="img"
aria-label="Abstract geometric pattern"
className="decorative-illustration"
/>
Support prefers-reduced-motion:
const prefersReducedMotion = window.matchMedia(
'(prefers-reduced-motion: reduce)'
).matches;
<video
autoPlay={!prefersReducedMotion}
controls={prefersReducedMotion}
muted
playsinline
/>
Pause timers when tab is hidden:
let timeoutId;
let remainingTime;
let startTime;
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
clearTimeout(timeoutId);
remainingTime -= Date.now() - startTime;
} else {
startTime = Date.now();
timeoutId = setTimeout(callback, remainingTime);
}
});
Always use <button> for buttons:
<!-- Good -->
<button onClick={handleClick}>Click me</button>
<!-- Bad -->
<div onClick={handleClick}>Click me</div>
Prevent duplicate requests:
const [isSubmitting, setIsSubmitting] = useState(false);
<button
disabled={isSubmitting}
onClick={async () => {
setIsSubmitting(true);
await submitForm();
setIsSubmitting(false);
}}
>
{isSubmitting ? 'Submitting...' : 'Submit'}
</button>
Add scale on active for responsiveness:
.button:active {
transform: scale(0.97);
}
Add delay to prevent accidental activation:
.tooltip {
transition-delay: 200ms;
}
Sequential tooltips: Skip delay after first tooltip opens:
const [isWarm, setIsWarm] = useState(false);
// When any tooltip opens, set warm state
// Clear warm state after 300ms of no tooltip
Allow diagonal cursor movement to submenus:
.submenu-trigger::after {
content: '';
position: absolute;
clip-path: polygon(0 0, 100% 0, 100% 100%);
}
Make entire row clickable:
<label class="checkbox-row">
<input type="checkbox" />
<span>Remember me</span>
</label>
TOUCH:
├── @media (hover: hover) for hover effects
├── 44px minimum tap targets
├── touch-action: manipulation on controls
├── muted + playsinline for video autoplay
└── Detect OS for shortcut display
KEYBOARD:
├── visibility: hidden hides from tab order
├── inert attribute for inactive sections
├── scrollIntoView on focus
└── Focus trap in modals
FORMS:
├── Labels associated with inputs
├── Correct input types for keyboards
├── 16px minimum font (iOS zoom)
├── <form> wrapper for Enter submission
└── No autofocus on touch devices
ACCESSIBILITY:
├── aria-label on icon buttons
├── role="img" + aria-label on decorative
├── prefers-reduced-motion support
└── Pause timers on tab hide
BUTTONS:
├── Always use <button> element
├── Disable during submission
└── transform: scale(0.97) on :active
Touch:
├── [ ] Hover effects gated by @media (hover: hover)
├── [ ] All tap targets >= 44px
├── [ ] touch-action set appropriately
└── [ ] Videos have muted + playsinline
Keyboard:
├── [ ] Tab order is logical
├── [ ] Hidden elements removed from tab order
├── [ ] Focus managed in modals
└── [ ] Scroll into view on focus
Forms:
├── [ ] All inputs have labels
├── [ ] Correct input types used
├── [ ] Font size >= 16px
├── [ ] Form wrapper for submission
└── [ ] No autofocus on touch
Accessibility:
├── [ ] Icon buttons have aria-label
├── [ ] Reduced motion supported
├── [ ] Timers pause when hidden
└── [ ] Semantic elements used