# Stable Font Weight on Hover

**NEVER** · **ID:** `content-font-weight-hover-stable` · **Category:** content
**Source:** [Rauno](https://interfaces.rauno.me/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/content-font-weight-hover-stable

> NEVER: Change `font-weight` on hover or selected state — bolder text takes more space and reflows its neighbors. Reserve the space up front (or use color/background/opacity instead).

Font weight should not change on hover or selected state to prevent layout shift

Changing font weight on hover causes text to take up different amounts of space, which shifts surrounding content. Use color, background, or opacity changes instead to indicate hover and selected states.

## Rule snippet

```tsx
/* reserve bold width so the label never reflows */
.item::after { content: attr(data-label); font-weight: 600; height: 0; visibility: hidden; }
```

## Bad — do not do this

`content-font-weight-hover-stable-bad`

```tsx
import { useState } from 'react';

export function FontWeightHoverStableBad() {
  const [hovered, setHovered] = useState<number | null>(null);
  const items = ['Dashboard', 'Analytics', 'Settings', 'Profile'];

  return (
    <div className="w-full max-w-sm space-y-4">
      <nav className="bg-card border border-border rounded-lg p-2">
        {items.map((item, i) => (
          <button
            key={item}
            onMouseEnter={() => setHovered(i)}
            onMouseLeave={() => setHovered(null)}
            className={`block w-full text-left px-3 py-2 rounded text-sm transition-colors ${
              hovered === i
                ? 'font-bold text-foreground bg-muted'
                : 'font-normal text-muted-foreground'
            }`}
          >
            {item}
          </button>
        ))}
      </nav>
      <p className="text-xs text-error">Font weight changes on hover — causes layout shift</p>
    </div>
  );
}
```

## Good — do this

`content-font-weight-hover-stable-good`

```tsx
import { useState } from 'react';

export function FontWeightHoverStableGood() {
  const [hovered, setHovered] = useState<number | null>(null);
  const items = ['Dashboard', 'Analytics', 'Settings', 'Profile'];

  return (
    <div className="w-full max-w-sm space-y-4">
      <nav className="bg-card border border-border rounded-lg p-2">
        {items.map((item, i) => (
          <button
            key={item}
            onMouseEnter={() => setHovered(i)}
            onMouseLeave={() => setHovered(null)}
            className={`block w-full text-left px-3 py-2 rounded text-sm font-medium transition-colors ${
              hovered === i
                ? 'text-foreground bg-muted'
                : 'text-muted-foreground'
            }`}
          >
            {item}
          </button>
        ))}
      </nav>
      <p className="text-xs text-success">Consistent font weight — only color and background change</p>
    </div>
  );
}
```

## References

- [interfaces.rauno.me](https://interfaces.rauno.me/)
