Motion & GSAP UI for React. Built for shadcn/ui.
Sora UI

Highlight

A shared motion highlight that slides between items on hover, or fades per-item on click.

Made by Axyl

A shared pill highlight slides between nav items on hover — move slowly to see the spring.

Loading...

Examples

Click Mode

A per-item fade background activated on click, useful for menus and sidebars.

Loading...

Installation

Usage

Parent mode — shared sliding element

One motion.div lives inside the container and slides to whichever item is active. This is the same pattern used by the sidebar hover highlight.

import { Highlight, HighlightItem } from '@/components/sora-ui/primitives/effects/highlight';

const ITEMS = ['Design', 'Engineering', 'Product'];

export default function NavBar() {
  return (
    <Highlight
      mode="parent"
      trigger="hover"
      className="rounded-full bg-foreground/8"
      containerClassName="flex items-center"
    >
      {ITEMS.map((item) => (
        <HighlightItem key={item} value={item}>
          <button className="px-4 py-1.5 text-sm" type="button">
            {item}
          </button>
        </HighlightItem>
      ))}
    </Highlight>
  );
}

Children mode — per-item fade

Each item renders its own motion.div overlay. Framer Motion's layoutId animates between items on click.

import { Highlight, HighlightItem } from '@/components/sora-ui/primitives/effects/highlight';

export default function Menu() {
  return (
    <Highlight
      mode="children"
      trigger="click"
      defaultValue="inbox"
      className="rounded-md bg-foreground/8"
    >
      {['Inbox', 'Drafts', 'Sent'].map((label) => (
        <HighlightItem key={label} value={label}>
          <button className="w-full px-3 py-2 text-sm text-left" type="button">
            {label}
          </button>
        </HighlightItem>
      ))}
    </Highlight>
  );
}

Controlled value

const [active, setActive] = React.useState<string | null>('design');

<Highlight
  mode="parent"
  trigger="click"
  value={active}
  onValueChange={setActive}
  className="rounded-lg bg-accent"
>
  ...
</Highlight>

Props

Highlight

PropTypeDefault
mode?
"parent" | "children"
"children"
trigger?
"hover" | "click"
"click"
value?
string | null
-
defaultValue?
string | null
-
onValueChange?
(value: string | null) => void
-
className?
string
-
style?
CSSProperties
-
transition?
Transition
{ type: "spring", stiffness: 350, damping: 35 }
exitDelay?
number
0
disabled?
boolean
false
containerClassName?
string
-
boundsOffset?
Partial<{ top: number; left: number; width: number; height: number }>
-

HighlightItem

PropTypeDefault
value?
string
-
disabled?
boolean
false
activeClassName?
string
-
className?
string
-
style?
CSSProperties
-
transition?
Transition
-
asChild?
boolean
false

When to Use

Use mode="parent" for navigation bars, tab rows, and any horizontal/vertical list where you want one smooth background element sliding between items. The spring physics make the motion feel natural even when the cursor skips quickly across items.

Use mode="children" for menus, sidebars, and selection lists where each item independently fades in its background. The shared layoutId cross-fades between items on click.

Avoid using trigger="hover" with mode="children" and widely-spaced items — the per-item fade-in/out can feel noisy. In that case, prefer mode="parent" which slides a single element.

Accessibility

HighlightItem sets aria-selected and data-active on each item wrapper. The highlight overlay itself is decorative (pointer-events-none) and invisible to assistive technologies. Keyboard navigation is not wired automatically — connect it via the controlled value/onValueChange API if needed.

When prefers-reduced-motion: reduce is set, Framer Motion automatically reduces the spring animation to a simple fade.

Built by Axyl. A motion-first component registry for React.

Last updated: 6/30/2026