Modifiers

Structural

Create structural modifiers for targeting elements by their position in the DOM tree with full type safety.

Overview

Structural modifiers let you apply utility styles conditionally based on an element's position within its parent. They wrap utility declarations in CSS structural pseudo-class selectors like :first-child, :last-child, and :nth-child(), generating variant utility classes that target elements by position.

Why Use Structural Modifiers?

Structural modifiers help you:

  • Style list items differently: Apply unique styles to the first, last, or alternating items
  • Create zebra striping: Use odd/even modifiers for table rows or list items
  • Remove redundant borders: Remove top/bottom borders on first/last items
  • Handle edge cases: Style only-child or empty elements differently
  • Build dynamic layouts: Adapt styling based on element position without JavaScript

useFirstModifier

The useFirstModifier() function creates a modifier that applies styles to the first child element.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useBorderWidthUtility, useBorderRadiusUtility } from "@styleframe/theme";
import { useFirstModifier } from "@styleframe/theme";

const s = styleframe();

const first = useFirstModifier(s);

useBorderWidthUtility(s, {
    0: '0',
}, [first]);

useBorderRadiusUtility(s, {
    'top-md': '0.375rem 0.375rem 0 0',
}, [first]);

export default s;

CSS Selector

Modifier NameCSS Selector
first&:first-child

useLastModifier

The useLastModifier() function creates a modifier that applies styles to the last child element.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useBorderWidthUtility } from "@styleframe/theme";
import { useLastModifier } from "@styleframe/theme";

const s = styleframe();

const last = useLastModifier(s);

useBorderWidthUtility(s, {
    0: '0',
}, [last]);

export default s;

CSS Selector

Modifier NameCSS Selector
last&:last-child

useOnlyModifier

The useOnlyModifier() function creates a modifier that applies styles when an element is the only child.

CSS Selector

Modifier NameCSS Selector
only&:only-child

useOddModifier

The useOddModifier() function creates a modifier that applies styles to odd-numbered children (1st, 3rd, 5th, etc.).

styleframe.config.ts
import { styleframe } from "styleframe";
import { useBackgroundColorUtility } from "@styleframe/theme";
import { useOddModifier, useEvenModifier } from "@styleframe/theme";

const s = styleframe();

const odd = useOddModifier(s);
const even = useEvenModifier(s);

useBackgroundColorUtility(s, {
    white: '#ffffff',
    light: '#f8f9fa',
}, [odd, even]);

export default s;

CSS Selector

Modifier NameCSS Selector
odd&:nth-child(odd)

useEvenModifier

The useEvenModifier() function creates a modifier that applies styles to even-numbered children (2nd, 4th, 6th, etc.).

CSS Selector

Modifier NameCSS Selector
even&:nth-child(even)

useFirstOfTypeModifier

The useFirstOfTypeModifier() function creates a modifier that applies styles to the first element of its type among siblings.

CSS Selector

Modifier NameCSS Selector
first-of-type&:first-of-type

useLastOfTypeModifier

The useLastOfTypeModifier() function creates a modifier that applies styles to the last element of its type among siblings.

CSS Selector

Modifier NameCSS Selector
last-of-type&:last-of-type

useOnlyOfTypeModifier

The useOnlyOfTypeModifier() function creates a modifier that applies styles when an element is the only one of its type among siblings.

CSS Selector

Modifier NameCSS Selector
only-of-type&:only-of-type

useEmptyModifier

The useEmptyModifier() function creates a modifier that applies styles to elements with no children.

styleframe.config.ts
import { styleframe } from "styleframe";
import { useDisplayUtility } from "@styleframe/theme";
import { useEmptyModifier } from "@styleframe/theme";

const s = styleframe();

const empty = useEmptyModifier(s);

useDisplayUtility(s, {
    none: 'none',
}, [empty]);

export default s;

CSS Selector

Modifier NameCSS Selector
empty&:empty

useStructuralModifiers

The useStructuralModifiers() function registers all structural modifiers at once and returns them as a destructurable object.

Returned Modifiers

KeyModifier NameCSS Selector
firstfirst&:first-child
lastlast&:last-child
onlyonly&:only-child
oddodd&:nth-child(odd)
eveneven&:nth-child(even)
firstOfTypefirst-of-type&:first-of-type
lastOfTypelast-of-type&:last-of-type
onlyOfTypeonly-of-type&:only-of-type
emptyempty&:empty

Examples

List with Border Separators

styleframe.config.ts
import { styleframe } from "styleframe";
import {
    useBorderWidthUtility,
    useBorderRadiusUtility,
    usePaddingUtility,
} from "@styleframe/theme";
import { useStructuralModifiers } from "@styleframe/theme";

const s = styleframe();

const { first, last } = useStructuralModifiers(s);

useBorderWidthUtility(s, {
    'top-0': '0',
}, [first]);

useBorderRadiusUtility(s, {
    'top-md': '0.375rem 0.375rem 0 0',
    'bottom-md': '0 0 0.375rem 0.375rem',
    0: '0',
}, [first, last]);

export default s;

Zebra-Striped Data Table

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

const s = styleframe();

const odd = useOddModifier(s);
const hover = useHoverModifier(s);

useBackgroundColorUtility(s, {
    light: '#f8f9fa',
    highlight: '#e9ecef',
}, [odd, hover]);

export default s;

Best Practices

  • Use first/last for border cleanup: Remove redundant borders on first and last items in lists
  • Prefer odd/even for zebra striping: More maintainable than manually alternating classes
  • Combine with hover: Add hover effects alongside structural modifiers for interactive lists and tables
  • Use empty for conditional display: Hide containers that have no content without JavaScript
  • Use first-of-type/last-of-type carefully: They match by element type, not by class, which can produce unexpected results in mixed-content containers

FAQ