home / skills / fusengine / agents / interactive-states

This skill helps implement and validate interactive button and input states using motion, focus, and loading cues for accessible UI.

npx playbooks add skill fusengine/agents --skill interactive-states

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
2.5 KB
---
name: interactive-states
description: Use when implementing button states, form field states, or interactive feedback. Covers hover, active, focus, disabled, loading states.
versions:
  framer-motion: "11"
user-invocable: true
allowed-tools: Read, Write, Edit, Glob, Grep
related-skills: adding-animations, generating-components
---

# Interactive States

## Agent Workflow (MANDATORY)

Before implementation, use `TeamCreate` to spawn 3 agents:

1. **fuse-ai-pilot:explore-codebase** - Check existing state patterns
2. **fuse-ai-pilot:research-expert** - Framer Motion state animations

After: Run **fuse-ai-pilot:sniper** for validation.

---

## Overview

| State | Visual | Timing |
|-------|--------|--------|
| Default | Base appearance | - |
| Hover | Scale/color change | 50-100ms |
| Pressed | Scale down | 100-150ms |
| Focus | Ring outline | instant |
| Disabled | Opacity 50% | - |
| Loading | Spinner | - |

---

## Quick Reference

### Button States

```tsx
<motion.button
  whileHover={{ scale: 1.02 }}
  whileTap={{ scale: 0.98 }}
  transition={{ duration: 0.1 }}
  className={cn(
    "px-4 py-2 rounded-lg bg-primary",
    "focus:outline-none focus-visible:ring-2",
    "disabled:opacity-50 disabled:cursor-not-allowed",
  )}
>
  {isLoading ? <Spinner /> : children}
</motion.button>
```

### Card Hover

```tsx
<motion.div
  whileHover={{
    y: -4,
    boxShadow: "0 25px 50px -12px rgb(0 0 0 / 0.15)",
  }}
  transition={{ duration: 0.2 }}
>
```

### Input States

```tsx
const inputStates = {
  default: "border-border bg-surface",
  focus: "border-primary ring-2 ring-primary/20",
  valid: "border-success bg-success/5",
  error: "border-destructive bg-destructive/5",
  disabled: "border-muted bg-muted/50 cursor-not-allowed",
};
```

### Focus Visible

```tsx
className="focus:outline-none focus-visible:ring-2 focus-visible:ring-primary"
```

### Loading State

```tsx
<button disabled={isLoading}>
  {isLoading ? (
    <Loader2 className="h-4 w-4 animate-spin" />
  ) : (
    "Submit"
  )}
</button>
```

---

## Validation Checklist

```
[ ] All 5 states defined (default, hover, active, focus, disabled)
[ ] Loading state with spinner
[ ] Hover timing 50-100ms
[ ] Focus visible for keyboard users
[ ] Disabled prevents interaction
```

---

## Best Practices

### DO
- Use Framer Motion for hover/tap
- Visible focus for accessibility
- Spinner for loading states
- Consistent timing across app

### DON'T
- Skip focus states
- Forget loading feedback
- Use slow animations (>200ms)
- Remove outline without replacement

Overview

This skill helps implement consistent interactive states for UI components such as buttons, inputs, and cards. It defines visual behavior for hover, active/pressed, focus, disabled, and loading states with recommended timing and accessibility considerations. The guidance includes Framer Motion patterns, CSS utility examples, and a validation checklist to ensure coverage.

How this skill works

The skill inspects component implementations and applies state patterns: motion-driven hover and tap animations, visible focus rings for keyboard users, opacity and cursor changes for disabled elements, and spinners for loading. It provides concrete code snippets and timing guidelines (50–150ms ranges) and validates presence of all required states and loading feedback. Use the provided input and button patterns as drop-in examples and adapt tokens for your design system.

When to use it

  • When building or reviewing interactive components (buttons, inputs, cards).
  • When adding motion or hover/press feedback to UI elements.
  • When enforcing accessibility for focus-visible outlines and keyboard navigation.
  • When implementing loading states and disabling interactions during async operations.
  • When standardizing timing and animation across an application.

Best practices

  • Use Framer Motion (or similar) for subtle hover and tap animations with duration 50–150ms.
  • Ensure focus is visible (focus-visible ring) for keyboard users, not just mouse users.
  • Provide a spinner and set disabled to true during loading to prevent duplicate actions.
  • Keep animation timings consistent across components and avoid slow animations (>200ms).
  • Use reduced opacity and cursor-not-allowed for disabled elements and preserve semantic disabled attribute.

Example use cases

  • Primary action button: whileHover scale up 1.02, whileTap scale down 0.98, show spinner and disabled during submit.
  • Card hover: lift card by y: -4 and increase box-shadow for hoverable previews.
  • Form input states: swap border and background tokens for default, focus, valid, error, and disabled states.
  • Accessible keyboard focus: add focus-visible:ring to all interactive controls so keyboard users see focus outlines.
  • Async flows: disable related controls and show inline spinner while awaiting API response.

FAQ

What timing should I use for hover and press animations?

Use 50–100ms for hover transitions and 100–150ms for pressed/active feedback to keep interactions snappy.

How should loading states be handled?

Render a compact spinner, set disabled on the control, and ensure focus and aria attributes reflect the busy state so screen readers are informed.