# Don't Rebuild Keyboard Behavior

**NEVER** · **ID:** `interactions-ibelick-manual-behavior` · **Category:** interactions
**Source:** [@Ibelick](https://www.ui-skills.com/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/interactions-ibelick-manual-behavior

> NEVER: Rebuild keyboard or focus behavior by hand unless explicitly requested. Use established primitives. Hand-rolled accessibility is usually incomplete.

Avoid manually implementing keyboard navigation and focus management that libraries handle correctly

Manual keyboard handling is error-prone. Hand-rolled versions routinely miss RTL arrow direction, skipping disabled items, type-ahead search, focus restoration on close, and roving tabindex. The escape hatch in the rule is real, though: if someone explicitly asks for custom behavior a primitive cannot express, build it — deliberately, not by accident.

## Bad — do not do this

`interactions-ibelick-manual-behavior-bad`

```tsx
import { useState, useRef, useEffect } from 'react';

export function IbelickManualBehaviorBad() {
  const [activeIndex, setActiveIndex] = useState(0);
  const items = ['Home', 'Profile', 'Settings'];
  const itemsRef = useRef<(HTMLButtonElement | null)[]>([]);

  // Manual keyboard navigation - incomplete implementation
  const handleKeyDown = (e: React.KeyboardEvent, index: number) => {
    if (e.key === 'ArrowDown') {
      e.preventDefault();
      const next = (index + 1) % items.length;
      setActiveIndex(next);
      itemsRef.current[next]?.focus();
    } else if (e.key === 'ArrowUp') {
      e.preventDefault();
      const prev = (index - 1 + items.length) % items.length;
      setActiveIndex(prev);
      itemsRef.current[prev]?.focus();
    }
  };

  useEffect(() => {
    itemsRef.current[activeIndex]?.focus();
  }, [activeIndex]);

  return (
    <div className="space-y-4">
      <div className="p-2 bg-muted rounded-lg" role="listbox">
        {items.map((item, i) => (
          <button
            key={item}
            ref={(el) => { itemsRef.current[i] = el; }}
            role="option"
            aria-selected={i === activeIndex}
            onKeyDown={(e) => handleKeyDown(e, i)}
            onClick={() => setActiveIndex(i)}
            className={`w-full text-left px-3 py-2 rounded ${
              i === activeIndex ? 'bg-primary text-primary-foreground' : 'hover:bg-muted-foreground/10'
            }`}
          >
            {item}
          </button>
        ))}
      </div>
      <p className="text-xs text-destructive">
        Manual keyboard handling misses: Home/End, type-ahead, disabled items, RTL
      </p>
    </div>
  );
}
```

## Good — do this

`interactions-ibelick-manual-behavior-good`

```tsx
import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs';

export function IbelickManualBehaviorGood() {
  // Using Radix Tabs - all keyboard behavior is built-in:
  // Arrow keys, Home/End, type-ahead, focus management, ARIA roles

  return (
    <div className="space-y-4">
      <Tabs defaultValue="home" className="w-full">
        <TabsList className="w-full">
          <TabsTrigger value="home" className="flex-1">Home</TabsTrigger>
          <TabsTrigger value="profile" className="flex-1">Profile</TabsTrigger>
          <TabsTrigger value="settings" className="flex-1">Settings</TabsTrigger>
        </TabsList>
        <TabsContent value="home" className="p-3 bg-muted rounded-lg mt-2">
          <p className="text-sm text-muted-foreground">Home content</p>
        </TabsContent>
        <TabsContent value="profile" className="p-3 bg-muted rounded-lg mt-2">
          <p className="text-sm text-muted-foreground">Profile content</p>
        </TabsContent>
        <TabsContent value="settings" className="p-3 bg-muted rounded-lg mt-2">
          <p className="text-sm text-muted-foreground">Settings content</p>
        </TabsContent>
      </Tabs>
      <p className="text-xs text-success">
        Radix handles: arrows, Home/End, type-ahead, disabled items, focus restore
      </p>
    </div>
  );
}
```

## References

- [ibelick/ui-skills — baseline-ui](https://github.com/ibelick/ui-skills)
- [WAI-ARIA Authoring Practices](https://www.w3.org/WAI/ARIA/apg/)
