Skip to main content

Hover Highlight

Hover Highlight is a wrapper that moves a shared background between rows, such as navigation links or menu actions.

Import

import { HoverHighlight } from '@vortexlabs/vortex';
import type { HoverHighlightProps } from '@vortexlabs/vortex';

Allied components

Other links

import { HoverHighlight, Interactive, Stack, Text } from "@vortexlabs/vortex";

const rowStyle = {
  padding: "var(--vortex-spacing-2xs) var(--vortex-spacing-sm)",
  borderRadius: "var(--vortex-border-radius-2xs)",
};

<Stack
  width="280px"
  maxWidth="100%"
  padding={1}
  borderColor="default"
  borderRadius="sm"
  backgroundColor="surface"
>
  <HoverHighlight>
    <Interactive href="/docs/introduction" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Introduction
      </Text>
    </Interactive>
    <Interactive href="/docs/quick-start" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Quick Start
      </Text>
    </Interactive>
    <Interactive href="/docs/all-components" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        All Components
      </Text>
    </Interactive>
  </HoverHighlight>
</Stack>;

Features

  • Moves one highlight between hovered or focused rows.
  • Can skip headings, separators, or other children.
  • Supports custom colors, images, and corner radius.
  • Sets fade, movement, and resize durations.

Appearance

Set backgroundColor and borderRadius to CSS values, including theme variables. Keep row backgrounds transparent so the highlight stays visible.

<Stack
  width="280px"
  maxWidth="100%"
  padding={1}
  borderColor="default"
  borderRadius="sm"
  backgroundColor="surface"
>
  <HoverHighlight
    backgroundColor="var(--vortex-color-background-primary-subtlest)"
    borderRadius="12px"
  >
    <Interactive href="/docs/introduction" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Introduction
      </Text>
    </Interactive>
    <Interactive href="/docs/quick-start" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Quick Start
      </Text>
    </Interactive>
    <Interactive href="/docs/all-components" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        All Components
      </Text>
    </Interactive>
  </HoverHighlight>
</Stack>;

Background Images

Set backgroundImage to a CSS gradient or image.

<Stack
  width="280px"
  maxWidth="100%"
  padding={1}
  borderColor="default"
  borderRadius="sm"
  backgroundColor="surface"
>
  <HoverHighlight
    backgroundColor="transparent"
    backgroundImage="linear-gradient(90deg, var(--vortex-color-background-primary-subtlest), transparent)"
  >
    <Interactive href="/docs/introduction" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Introduction
      </Text>
    </Interactive>
    <Interactive href="/docs/quick-start" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Quick Start
      </Text>
    </Interactive>
    <Interactive href="/docs/all-components" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        All Components
      </Text>
    </Interactive>
  </HoverHighlight>
</Stack>;

Choosing Targets

Place one row in each direct child. Return false from isHighlightable to skip headings or separators.

"use client";

import { HoverHighlight, Interactive, Stack, Text } from "@vortexlabs/vortex";

const rowStyle = {
  padding: "var(--vortex-spacing-2xs) var(--vortex-spacing-sm)",
  borderRadius: "var(--vortex-border-radius-2xs)",
};

export const HighlightTargets = () => {
  return (
    <Stack
      width="280px"
      maxWidth="100%"
      padding={1}
      borderColor="default"
      borderRadius="sm"
      backgroundColor="surface"
    >
      <HoverHighlight isHighlightable={(child) => child.type === Interactive}>
        <Text size="body-sm-desktop" color="subtle">
          Documentation
        </Text>
        <Interactive
          href="/docs/introduction"
          fullWidth
          insetFocus
          attributes={{ style: rowStyle }}
        >
          <Text as="span" size="body-md-desktop">
            Introduction
          </Text>
        </Interactive>
        <Interactive href="/docs/quick-start" fullWidth insetFocus attributes={{ style: rowStyle }}>
          <Text as="span" size="body-md-desktop">
            Quick Start
          </Text>
        </Interactive>
      </HoverHighlight>
    </Stack>
  );
};

Transition Timing

Set initialDelay for opacity and transitionDelay for movement and resizing, in milliseconds. Use 0 to remove the corresponding transition.

<Stack
  width="280px"
  maxWidth="100%"
  padding={1}
  borderColor="default"
  borderRadius="sm"
  backgroundColor="surface"
>
  <HoverHighlight initialDelay={0} transitionDelay={120}>
    <Interactive href="/docs/introduction" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Introduction
      </Text>
    </Interactive>
    <Interactive href="/docs/quick-start" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        Quick Start
      </Text>
    </Interactive>
    <Interactive href="/docs/all-components" fullWidth insetFocus attributes={{ style: rowStyle }}>
      <Text as="span" size="body-md-desktop">
        All Components
      </Text>
    </Interactive>
  </HoverHighlight>
</Stack>;

Focus Synchronization

Set syncPseudoFocus to follow changes to Vortex’s data-vortex-focus attribute. The parent widget must provide keyboard navigation.

Accessibility

Description
Use labelled links or buttons for interactive children; the highlight adds no keyboard behavior.
Preserve each child's visible focus indicator; the highlight does not communicate selection.