Modifiers

Pseudo-State

Create pseudo-state modifiers for interactive states like hover, focus, active, and more with full type safety.

Overview

Pseudo-state modifiers let you apply utility styles conditionally based on user interaction states. They wrap utility declarations in CSS pseudo-class selectors like :hover, :focus, and :active, generating variant utility classes that respond to user behavior.

Why Use Pseudo-State Modifiers?

Pseudo-state modifiers help you:

  • Create interactive UIs: Apply styles when users hover, focus, or click on elements
  • Build accessible interfaces: Use focus-visible for keyboard-only focus indicators
  • Generate state variants: Automatically create hover, focus, and active versions of any utility
  • Keep styling declarative: Express interactive states directly in your HTML class names

useHoverModifier

The useHoverModifier() function creates a modifier that applies styles when the user hovers over an element.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useColor } from "@styleframe/theme";
import { useBackgroundColorUtility } from "@styleframe/theme";
import { useHoverModifier } from "@styleframe/theme";

const s = styleframe();
const { ref } = s;

const { colorPrimary, colorSecondary } = useColor(s, {
    primary: '#006cff',
    secondary: '#6c757d',
} as const);

const hover = useHoverModifier(s);

useBackgroundColorUtility(s, {
    primary: ref(colorPrimary),
    secondary: ref(colorSecondary),
}, [hover]);

export default s;

CSS Selector

Modifier NameCSS Selector
hover&:hover

useFocusModifier

The useFocusModifier() function creates a modifier that applies styles when an element receives focus.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useRingUtility } from "@styleframe/theme";
import { useFocusModifier } from "@styleframe/theme";

const s = styleframe();

const focus = useFocusModifier(s);

useRingUtility(s, {
    primary: '0 0 0 2px #006cff',
}, [focus]);

export default s;

CSS Selector

Modifier NameCSS Selector
focus&:focus

useFocusWithinModifier

The useFocusWithinModifier() function creates a modifier that applies styles when any child element receives focus.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useBorderColorUtility } from "@styleframe/theme";
import { useFocusWithinModifier } from "@styleframe/theme";

const s = styleframe();

const focusWithin = useFocusWithinModifier(s);

useBorderColorUtility(s, {
    primary: '#006cff',
}, [focusWithin]);

export default s;

CSS Selector

Modifier NameCSS Selector
focus-within&:focus-within

useFocusVisibleModifier

The useFocusVisibleModifier() function creates a modifier that applies styles only when focus is visible (typically keyboard navigation).

styleframe.config.ts
import { styleframe } from "styleframe";
import { useOutlineUtility } from "@styleframe/theme";
import { useFocusVisibleModifier } from "@styleframe/theme";

const s = styleframe();

const focusVisible = useFocusVisibleModifier(s);

useOutlineUtility(s, {
    primary: '2px solid #006cff',
}, [focusVisible]);

export default s;

CSS Selector

Modifier NameCSS Selector
focus-visible&:focus-visible
Pro tip: Prefer useFocusVisibleModifier over useFocusModifier for focus indicators. It only shows the indicator for keyboard navigation, not mouse clicks, providing a cleaner user experience.

useActiveModifier

The useActiveModifier() function creates a modifier that applies styles when an element is being activated (clicked/pressed).

styleframe.config.ts
import { styleframe } from "styleframe";
import { useScaleUtility } from "@styleframe/theme";
import { useActiveModifier } from "@styleframe/theme";

const s = styleframe();

const active = useActiveModifier(s);

useScaleUtility(s, {
    95: '0.95',
}, [active]);

export default s;

CSS Selector

Modifier NameCSS Selector
active&:active

useVisitedModifier

The useVisitedModifier() function creates a modifier that applies styles to visited links.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useTextColorUtility } from "@styleframe/theme";
import { useVisitedModifier } from "@styleframe/theme";

const s = styleframe();

const visited = useVisitedModifier(s);

useTextColorUtility(s, {
    muted: '#6c757d',
}, [visited]);

export default s;

CSS Selector

Modifier NameCSS Selector
visited&:visited

useTargetModifier

The useTargetModifier() function creates a modifier that applies styles when the element is the target of the current URL fragment.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useBackgroundColorUtility } from "@styleframe/theme";
import { useTargetModifier } from "@styleframe/theme";

const s = styleframe();

const target = useTargetModifier(s);

useBackgroundColorUtility(s, {
    highlight: '#fff3cd',
}, [target]);

export default s;

CSS Selector

Modifier NameCSS Selector
target&:target

usePseudoStateModifiers

The usePseudoStateModifiers() function registers all pseudo-state modifiers at once and returns them as a destructurable object.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useColor } from "@styleframe/theme";
import { useOpacityUtility } from "@styleframe/theme";
import { usePseudoStateModifiers } from "@styleframe/theme";

const s = styleframe();

const { hover, focus, active } = usePseudoStateModifiers(s);

useOpacityUtility(s, {
    75: '0.75',
    50: '0.5',
}, [hover, focus, active]);

export default s;

Returned Modifiers

KeyModifier NameCSS Selector
hoverhover&:hover
focusfocus&:focus
focusWithinfocus-within&:focus-within
focusVisiblefocus-visible&:focus-visible
activeactive&:active
visitedvisited&:visited
targettarget&:target

Examples

Interactive Button

styleframe.config.ts
import { styleframe } from "styleframe";
import { useColor } from "@styleframe/theme";
import { useBackgroundColorUtility, useScaleUtility, useOpacityUtility } from "@styleframe/theme";
import { usePseudoStateModifiers } from "@styleframe/theme";

const s = styleframe();
const { ref } = s;

const { colorPrimary } = useColor(s, { primary: '#006cff' } as const);

const { hover, active, focusVisible } = usePseudoStateModifiers(s);

useBackgroundColorUtility(s, {
    primary: ref(colorPrimary),
}, [hover]);

useOpacityUtility(s, {
    90: '0.9',
}, [hover]);

useScaleUtility(s, {
    95: '0.95',
}, [active]);

export default s;

Focus Ring with Focus-Visible

styleframe.config.ts
import { styleframe } from "styleframe";
import { useRingUtility, useOutlineUtility } from "@styleframe/theme";
import { useFocusVisibleModifier } from "@styleframe/theme";

const s = styleframe();

const focusVisible = useFocusVisibleModifier(s);

useRingUtility(s, {
    primary: '0 0 0 3px rgba(0, 108, 255, 0.5)',
}, [focusVisible]);

useOutlineUtility(s, {
    none: 'none',
}, [focusVisible]);

export default s;

Best Practices

  • Prefer focus-visible over focus: Use useFocusVisibleModifier for focus indicators to avoid showing focus rings on mouse clicks
  • Combine hover and active: Create buttons that respond to both hover and press states for better feedback
  • Use focus-within for form groups: Highlight parent containers when any child input is focused
  • Limit modifier count: Only generate the state variants your design requires to keep CSS bundle size small
  • Test touch devices: :hover may behave unexpectedly on touch devices; design fallbacks accordingly

FAQ