API Essentials

Selectors

Styleframe selectors allow you to create CSS rules with type-safe property definitions. They provide a powerful way to style your components.

Overview

Selectors are the core building blocks for creating styles in Styleframe. They allow you to define CSS rules with full type safety and auto-complete. Selectors can target HTML elements, classes, IDs, and use any valid CSS selector syntax while providing a clean TypeScript API for defining styles.

Why use selectors?

Selectors help you:

  • Write type-safe CSS: Get auto-complete and instant feedback in your editor for all CSS properties and values.
  • Prevent common mistakes: Eliminate typos and invalid CSS at compile time, before it hits the browser.
  • Compose styles with ease: Leverage variables and composables for reusable, scalable design patterns.
  • Generate clean, optimized output: Let Styleframe handle the generation of clean, optimized CSS output.

Defining Selectors

You define a selector using the selector() function from your styleframe instance:

import { styleframe } from 'styleframe';

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

selector('.button', {
    padding: '0.5rem 1rem',
    borderRadius: '4px',
    backgroundColor: '#006cff',
    color: 'white',
});

export default s;

Each selector takes a CSS selector string and a style declarations object with the properties and values you want to apply.

Pro tip: Use descriptive class names that reflect the component's purpose rather than its appearance. This makes your CSS more maintainable.

Nested Selectors

You can nest selectors to create more specific targeting and improve readability:

a. Callback Nesting

For more complex nesting scenarios or when you need to generate selectors dynamically, you can use the callback-based approach.

import { styleframe } from 'styleframe';

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

const nested = selector('.card', ({ selector }) => {
    selector('.card-title', {
        fontSize: '1.5rem',
        fontWeight: 'bold',
    });

    selector('.card-content', {
        marginTop: '0.5rem',
    });
    
    return {
        padding: '1rem',
        borderRadius: '8px'
    }
});

export default s;

When using the callback-based approach, you can return a style declarations object to apply to the parent selector.

b. Inline Nesting

Alternatively, you can use inline nesting syntax for simpler nested selector definitions:

import { styleframe } from 'styleframe';

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

selector('.card', {
    padding: '1rem',
    borderRadius: '8px',

    '.card-title': {
        fontSize: '1.5rem',
        fontWeight: 'bold'
    },

    '.card-content': {
        marginTop: '0.5rem'
    }
});

export default s;

Examples

Pseudo Classes and Elements

Styleframe supports all CSS pseudo-classes and pseudo-elements, as well as the new & nesting selector:

import { styleframe } from 'styleframe';

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

selector('.button', {
    padding: '0.5rem 1rem',
    backgroundColor: '#006cff',
    color: 'white',
    transition: 'background-color 0.2s',
    
    '&:hover': {
        backgroundColor: '#0056cc',
    },
    
    '&:active': {
        backgroundColor: '#004099',
    },
    
    '&::before': {
        content: '""',
        display: 'inline-block',
        marginRight: '0.5rem',
    },
});

export default s;

Using Variables with Selectors

To create a cohesive design system, combine selectors with variables:

import { styleframe } from 'styleframe';

const s = styleframe();
const { variable, ref, selector } = s;

const borderRadiusSm = variable('border-radius--sm', '4px');
const colorPrimary500 = variable('color--primary', '#006cff');
const colorPrimary600 = variable('color--primary-dark', '#0056cc');
const spacingMd = variable('spacing--md', '1rem');

selector('.button', {
    backgroundColor: ref(colorPrimary500),
    borderRadius: ref(borderRadiusSm),
    color: 'white',
    padding: ref(spacingMd),
    
    '&:hover': {
        backgroundColor: ref(colorPrimary600),
    },
});

export default s;

Best Practices

  • Group related selectors logically, either by component or functionality.
  • Use variables for values that might be reused or could change in the future.
  • Keep selectors focused on a single responsibility to improve maintainability.
  • Use descriptive class names that indicate purpose rather than appearance.
  • Leverage nesting for better organization, but avoid excessive nesting depths.

FAQ