Skip to content

Static Modifier API

The staticModifier function allows you to create modifiers with fixed CSS selectors. This is the simplest way to add custom modifiers (variants) to BaroCSS.

Basic Syntax

typescript
import { staticModifier } from '@barocss/kit';

staticModifier('modifier-name', [
  'selector1',
  'selector2'
], {
  // Optional configuration
});

Parameters

Required Parameters

  • name (string): The modifier name (e.g., 'hover', 'focus', 'dark')
  • selectors (string[]): Array of CSS selectors to apply when the modifier is used

Optional Parameters

typescript
interface StaticModifierOptions {
  source?: string;     // Source identifier for debugging
  sort?: number;       // Sort order for modifier processing

Wrapping Types

Understanding Wrapping Types

The wrappingType parameter controls how the modifier's selector is applied to the utility's CSS. This is crucial for creating the correct CSS structure and ensuring proper selector behavior.

Available Wrapping Types

'rule' (Default)

Purpose

Creates a standard CSS rule where the & placeholder is replaced with the actual class name.

typescript
// Input: hover:bg-blue-500
// Output: .hover\:bg-blue-500:hover { background-color: #3b82f6; }
staticModifier('hover', ['&:hover'], { source: 'pseudo' });

Use when: The & placeholder should be replaced with the actual class name to create proper CSS selectors.

'style-rule'

Purpose

Creates a style rule where the & placeholder remains as-is, preserving the structural selector.

typescript
// Input: [&>*]:bg-blue-500
// Output: .\[\&\>\*\]\:bg-blue-500 > * { background-color: #3b82f6; }
staticModifier('[&>*]', ['& > *'], { source: 'child' });

Use when: The & placeholder should remain as-is to create structural selectors like child or sibling selectors.

'at-rule'

Purpose

Creates an at-rule (like @media or @supports) that wraps the utility, creating the proper CSS structure for conditional styling.

typescript
// Input: print:bg-blue-500
// Output: @media print { .print\:bg-blue-500 { background-color: #3b82f6; } }
staticModifier('print', ['@media print'], { source: 'media' });

Use when: Creating media queries, container queries, or other at-rules that need to wrap the utility in a conditional structure.

When to Use Each Type

Wrapping TypeUse CaseExample SelectorResult
'rule'Standard pseudo-classes&:hover.class:hover
'rule'Attribute selectors&[data-state="open"].class[data-state="open"]
'rule'Parent selectors.parent &.parent .class
'style-rule'Child selectors& > *.class > *
'style-rule'Sibling selectors& ~ .sibling.class ~ .sibling
'at-rule'Media queries@media print@media print { .class { ... } }

Examples by Use Case

Pseudo-classes (use 'rule')

typescript
staticModifier('hover', ['&:hover'], { source: 'pseudo' });
staticModifier('focus', ['&:focus'], { source: 'pseudo' });
staticModifier('active', ['&:active'], { source: 'pseudo' });

Attribute selectors (use 'rule')

typescript
staticModifier('data-open', ['&[data-open]'], { source: 'data' });
staticModifier('aria-pressed', ['&[aria-pressed="true"]'], { source: 'aria' });

Child selectors (use 'style-rule')

typescript
staticModifier('[&>*]', ['& > *'], { source: 'child' });
staticModifier('[&~.sibling]', ['& ~ .sibling'], { source: 'sibling' });

Parent selectors (use 'rule')

typescript
staticModifier('group-hover', ['.group:hover &'], { source: 'group' });
staticModifier('peer-focus', ['.peer:focus ~ &'], { source: 'peer' });

Media queries (use 'at-rule')

typescript
staticModifier('print', ['@media print'], { source: 'media' });
staticModifier('screen', ['@media screen'], { source: 'media' });

Common Mistakes

❌ Wrong: Using 'style-rule' for simple selectors

typescript
// Don't do this
staticModifier('hover', ['&:hover'], { wrappingType: 'style-rule' });

✅ Correct: Using 'rule' for simple selectors

typescript
// Do this instead
staticModifier('hover', ['&:hover'], { source: 'pseudo' });

❌ Wrong: Using 'rule' for complex child selectors

typescript
// Don't do this
staticModifier('[&>*]', ['& > *'], { source: 'child' });

✅ Correct: Using 'style-rule' for complex child selectors

typescript
// Do this instead
staticModifier('[&>*]', ['& > *'], { wrappingType: 'style-rule', source: 'child' });

How Modifiers Work

Modifiers are used to conditionally apply styles based on certain states or conditions. When you use a modifier like hover:bg-blue-500, BaroCSS:

  1. Detects the hover: modifier
  2. Finds the corresponding modifier registration
  3. Applies the registered selectors to wrap the utility's CSS

Real-World Examples

1. Basic Pseudo-class Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Hover modifier
staticModifier('hover', ['&:hover'], { source: 'pseudo' });

// Focus modifier
staticModifier('focus', ['&:focus'], { source: 'pseudo' });

// Active modifier
staticModifier('active', ['&:active'], { source: 'pseudo' });

// Visited modifier
staticModifier('visited', ['&:visited'], { source: 'pseudo' });

2. Pseudo-element Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Before pseudo-element
staticModifier('before', ['&::before'], { source: 'pseudo' });

// After pseudo-element
staticModifier('after', ['&::after'], { source: 'pseudo' });

// First-line pseudo-element
staticModifier('first-line', ['&::first-line'], { source: 'pseudo' });

// First-letter pseudo-element
staticModifier('first-letter', ['&::first-letter'], { source: 'pseudo' });

3. Dark Mode Modifier

typescript
import { staticModifier } from '@barocss/kit';

// Class-based dark mode
staticModifier('dark', ['.dark', '.dark *'], { source: 'theme' });

// Data attribute-based dark mode
staticModifier('dark', ['[data-theme="dark"]', '[data-theme="dark"] *'], { source: 'theme' });

// Media query-based dark mode
staticModifier('dark', ['@media (prefers-color-scheme: dark)'], { source: 'media' });

4. Group Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Group hover - applies when parent has hover
staticModifier('group-hover', ['.group:hover &'], { source: 'group' });

// Group focus - applies when parent has focus
staticModifier('group-focus', ['.group:focus &'], { source: 'group' });

// Group active - applies when parent has active
staticModifier('group-active', ['.group:active &'], { source: 'group' });

5. Peer Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Peer hover - applies when sibling has hover
staticModifier('peer-hover', ['.peer:hover ~ &'], { source: 'peer' });

// Peer focus - applies when sibling has focus
staticModifier('peer-focus', ['.peer:focus ~ &'], { source: 'peer' });

// Peer checked - applies when sibling is checked
staticModifier('peer-checked', ['.peer:checked ~ &'], { source: 'peer' });

6. Complex Selector Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Not modifier - applies when element doesn't match selector
staticModifier('not-first', [':not(:first-child)'], { source: 'structural' });

// Not last modifier
staticModifier('not-last', [':not(:last-child)'], { source: 'structural' });

// Only child modifier
staticModifier('only-child', [':only-child'], { source: 'structural' });

// Empty modifier
staticModifier('empty', [':empty'], { source: 'structural' });

7. Form State Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Checked modifier
staticModifier('checked', ['&:checked'], { source: 'form' });

// Disabled modifier
staticModifier('disabled', ['&:disabled'], { source: 'form' });

// Required modifier
staticModifier('required', ['&:required'], { source: 'form' });

// Invalid modifier
staticModifier('invalid', ['&:invalid'], { source: 'form' });

// Valid modifier
staticModifier('valid', ['&:valid'], { source: 'form' });

8. Media Query Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Print modifier
staticModifier('print', ['@media print'], { source: 'media' });

// Screen modifier
staticModifier('screen', ['@media screen'], { source: 'media' });

// Reduced motion modifier
staticModifier('motion-reduce', ['@media (prefers-reduced-motion: reduce)'], { source: 'media' });

// High contrast modifier
staticModifier('motion-safe', ['@media (prefers-reduced-motion: no-preference)'], { source: 'media' });

9. Custom Theme Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Custom theme modifier
staticModifier('theme-midnight', ['[data-theme="midnight"]'], { source: 'theme' });

// Custom state modifier
staticModifier('loading', ['[data-state="loading"]'], { source: 'state' });

// Custom variant modifier
staticModifier('variant-primary', ['[data-variant="primary"]'], { source: 'variant' });

Advanced Patterns

1. Multiple Selectors

typescript
import { staticModifier } from '@barocss/kit';

// Modifier with multiple selectors
staticModifier('focus-visible', [
  '&:focus-visible',
  '&:focus:not(:focus-visible)'
], { source: 'pseudo' });

2. Complex Group Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Group modifier with complex selector
staticModifier('group-hover', [
  '.group:hover &',
  '.group:focus-within &'
], { source: 'group' });

3. Conditional Modifiers

typescript
import { staticModifier } from '@barocss/kit';

// Modifier that works with different parent classes
staticModifier('parent-hover', [
  '.parent:hover &',
  '[data-parent="hover"] &'
], { source: 'parent' });

Common Use Cases

1. Interactive States

typescript
// Basic interactive states
staticModifier('hover', ['&:hover']);
staticModifier('focus', ['&:focus']);
staticModifier('active', ['&:active']);
staticModifier('visited', ['&:visited']);

2. Form States

typescript
// Form input states
staticModifier('checked', ['&:checked']);
staticModifier('disabled', ['&:disabled']);
staticModifier('required', ['&:required']);
staticModifier('invalid', ['&:invalid']);
staticModifier('valid', ['&:valid']);

3. Structural Selectors

typescript
// Structural pseudo-classes
staticModifier('first-child', ['&:first-child']);
staticModifier('last-child', ['&:last-child']);
staticModifier('only-child', ['&:only-child']);
staticModifier('empty', ['&:empty']);

4. Theme Variants

typescript
// Theme-based modifiers
staticModifier('dark', ['.dark', '.dark *']);
staticModifier('light', ['.light', '.light *']);
staticModifier('theme-brand', ['[data-theme="brand"]']);

Released under the MIT License.