Modifiers

Directional

Create directional modifiers for targeting elements based on text direction (RTL/LTR) with full type safety.

Overview

Directional modifiers let you apply utility styles conditionally based on the text direction of the document or a parent element. They wrap utility declarations in CSS selectors that match either right-to-left (RTL) or left-to-right (LTR) contexts, generating variant utility classes that adapt to text direction.

Why Use Directional Modifiers?

Directional modifiers help you:

  • Support internationalization: Adapt layouts for RTL languages like Arabic, Hebrew, and Persian
  • Flip directional properties: Swap margins, paddings, and positions based on text direction
  • Build bidirectional components: Create components that work in both LTR and RTL contexts
  • Maintain zero specificity: The :where() wrapper prevents specificity conflicts

useRtlModifier

The useRtlModifier() function creates a modifier that applies styles in right-to-left contexts. It uses :where() to maintain zero specificity.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useMarginLeftUtility, useMarginRightUtility } from "@styleframe/theme";
import { useRtlModifier } from "@styleframe/theme";

const s = styleframe();

const rtl = useRtlModifier(s);

useMarginLeftUtility(s, {
    md: '1rem',
    0: '0',
}, [rtl]);

useMarginRightUtility(s, {
    md: '1rem',
    0: '0',
}, [rtl]);

export default s;

CSS Selector

Modifier NameCSS Selector
rtl&:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *)
Pro tip: The RTL modifier uses :where() to keep specificity at zero. This prevents the RTL variant from winning over other utility classes due to specificity, making the cascade more predictable.

useLtrModifier

The useLtrModifier() function creates a modifier that applies styles in left-to-right contexts. Like the RTL modifier, it uses :where() for zero specificity.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useTextAlignUtility } from "@styleframe/theme";
import { useLtrModifier, useRtlModifier } from "@styleframe/theme";

const s = styleframe();

const ltr = useLtrModifier(s);
const rtl = useRtlModifier(s);

useTextAlignUtility(s, {
    left: 'left',
    right: 'right',
}, [ltr, rtl]);

export default s;

CSS Selector

Modifier NameCSS Selector
ltr&:where(:dir(ltr), [dir="ltr"], [dir="ltr"] *)

useDirectionalModifiers

The useDirectionalModifiers() function registers both directional modifiers at once and returns them as a destructurable object.

styleframe.config.ts
import { styleframe } from "styleframe";
import { usePaddingLeftUtility, usePaddingRightUtility } from "@styleframe/theme";
import { useDirectionalModifiers } from "@styleframe/theme";

const s = styleframe();

const { rtl, ltr } = useDirectionalModifiers(s);

usePaddingLeftUtility(s, {
    md: '1rem',
    0: '0',
}, [rtl, ltr]);

usePaddingRightUtility(s, {
    md: '1rem',
    0: '0',
}, [rtl, ltr]);

export default s;

Returned Modifiers

KeyModifier NameCSS Selector
rtlrtl&:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *)
ltrltr&:where(:dir(ltr), [dir="ltr"], [dir="ltr"] *)

Examples

Bidirectional Navigation

styleframe.config.ts
import { styleframe } from "styleframe";
import {
    useMarginLeftUtility,
    useMarginRightUtility,
    usePaddingLeftUtility,
    usePaddingRightUtility,
} from "@styleframe/theme";
import { useDirectionalModifiers } from "@styleframe/theme";

const s = styleframe();

const { rtl } = useDirectionalModifiers(s);

useMarginLeftUtility(s, { auto: 'auto', 0: '0' }, [rtl]);
useMarginRightUtility(s, { auto: 'auto', 0: '0' }, [rtl]);

usePaddingLeftUtility(s, { md: '1rem', 0: '0' }, [rtl]);
usePaddingRightUtility(s, { md: '1rem', 0: '0' }, [rtl]);

export default s;

Best Practices

  • Prefer logical properties: When possible, use CSS logical properties (margin-inline-start, padding-inline-end) instead of directional modifiers, as they handle RTL automatically
  • Use directional modifiers for exceptions: Apply them when logical properties don't cover your use case (e.g., absolute positioning, transforms)
  • Set dir attribute: Ensure your HTML has the correct dir="rtl" or dir="ltr" attribute for the selectors to match
  • Test both directions: Verify your layouts work correctly in both LTR and RTL modes
  • Keep specificity low: The :where() wrapper ensures directional modifiers don't cause specificity battles

FAQ