# Use will-change Sparingly

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

> NEVER: Apply will-change outside an active animation. It wastes GPU memory when not needed. Add dynamically before animation, remove after completion.

Only apply will-change during active animations, never as a permanent style

will-change is a promise, not an optimisation: it asks the browser to promote the element to its own compositor layer AHEAD of a change you are about to make. Left on permanently it is a promise you never keep — the layer is allocated, its memory is held, and nothing ever animates. Do it across a list and you get layer explosion, where the cost of compositing hundreds of layers exceeds whatever the promotion saved. ibelick's fixing-motion-performance skill states the discipline exactly: "use will-change temporarily and surgically", and "compositor motion requires layer promotion, never assume it" — so add it when the animation is about to start (or on hover, just before a press) and remove it when the animation ends.

## Bad — do not do this

`performance-ibelick-will-change-bad`

```tsx
export function IbelickWillChangeBad() {
  return (
    <div className="space-y-4">
      <div className="grid grid-cols-3 gap-2">
        {Array.from({ length: 9 }).map((_, i) => (
          <div
            key={i}
            className="p-4 bg-muted rounded-lg text-center text-sm hover:scale-105 transition-transform"
            style={{ willChange: 'transform, opacity, filter' }}
          >
            Item {i + 1}
          </div>
        ))}
      </div>
      <code className="block text-xs p-2 bg-muted rounded">
        style={'{'}{'{'} willChange: 'transform, opacity, filter' {'}'}{'}'}
      </code>
      <p className="text-xs text-destructive">
        Permanent will-change on every item wastes GPU memory
      </p>
    </div>
  );
}
```

## Good — do this

`performance-ibelick-will-change-good`

```tsx
export function IbelickWillChangeGood() {
  return (
    <div className="space-y-4">
      <div className="grid grid-cols-3 gap-2">
        {Array.from({ length: 9 }).map((_, i) => (
          <div
            key={i}
            className="p-4 bg-muted rounded-lg text-center text-sm hover:scale-105 transition-transform group"
          >
            <span className="group-hover:will-change-transform">Item {i + 1}</span>
          </div>
        ))}
      </div>
      <code className="block text-xs p-2 bg-muted rounded">
        className="hover:will-change-transform"
      </code>
      <p className="text-xs text-success">
        will-change only applied on hover - browser optimizes when needed
      </p>
    </div>
  );
}
```

## References

- [ibelick — baseline-ui SKILL.md](https://github.com/ibelick/ui-skills/blob/main/skills/baseline-ui/SKILL.md)
- [ibelick — fixing-motion-performance SKILL.md](https://github.com/ibelick/ui-skills/blob/main/skills/fixing-motion-performance/SKILL.md)
- [will-change MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/will-change)
