Design Tokens

Borders

Create and manage border design tokens with CSS variables for consistent border styles, widths, and colors across your application.

Overview

The border composables help you create comprehensive border systems with minimal code. They generate border-related variables that can be easily referenced throughout your application, enabling flexible theming and consistent visual boundaries for your components.

Why use border composables?

Border composables help you:

  • Centralize border definitions: Define all your border styles, widths, and colors in one place for easy management.
  • Enable flexible theming: Override border variables to instantly update component borders across your application.
  • Maintain consistency: Use semantic names to ensure consistent border usage throughout your design system.
  • Reduce repetition: Reference border variables instead of repeating CSS values throughout your stylesheets.
  • Separate concerns: Keep border colors semantically distinct from other color usage in your application.

useBorderStyle

The useBorderStyle() function creates a set of border style variables covering all standard CSS border styles.

import { styleframe } from 'styleframe';
import { useBorderStyle } from '@styleframe/theme';

const s = styleframe();

const {
    borderStyle,
    borderStyleNone,
    borderStyleSolid,
    borderStyleDashed,
    borderStyleDotted,
    borderStyleDouble,
    borderStyleGroove,
    borderStyleInset,
    borderStyleOutset,
} = useBorderStyle(s);

export default s;

The function creates variables for all standard CSS border styles and a default --border-style variable that references solid by default.

Creating Custom Border Style Variables

You can provide completely custom border style values if you need styles beyond the CSS standard keywords:

import { styleframe } from 'styleframe';
import { useBorderStyle } from '@styleframe/theme';

const s = styleframe();

const {
    borderStyle,
    borderStyleWavy,
    borderStyleHidden
} = useBorderStyle(s, {
    default: 'solid',
    wavy: 'wavy',  // Custom CSS value (if supported)
    hidden: 'hidden'
});

export default s;

Updating the Default Border Style Variable

You can override the default border style value after creating it by using variable():

import { styleframe } from 'styleframe';
import { useBorderStyle } from '@styleframe/theme';

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

const { borderStyle } = useBorderStyle(s);

// Override the default border style
variable(borderStyle, 'dashed');

export default s;

Extending the Default Border Style Values

You can customize which style is used as the default while keeping all other standard styles. Use the @ prefix to reference another key in the values object:

import { styleframe } from 'styleframe';
import { useBorderStyle, defaultBorderStyleValues } from '@styleframe/theme';

const s = styleframe();

const { borderStyle } = useBorderStyle(s, {
    ...defaultBorderStyleValues,
    default: '@dashed'
});

export default s;
Pro tip: Using a default --border-style variable makes it easy to change your entire application's border style by overriding just one variable, while still having specific style variants available when needed.

useBorderWidth

The useBorderWidth() function creates a set of border width variables for common border thickness levels.

import { styleframe } from 'styleframe';
import { useBorderWidth } from '@styleframe/theme';

const s = styleframe();

const {
    borderWidth,
    borderWidthNone,
    borderWidthThin,
    borderWidthMedium,
    borderWidthThick,
} = useBorderWidth(s);

export default s;

The function creates variables for standard CSS border widths including none (0), thin, medium, and thick. The default --border-width variable references thin by default.

Good to know: CSS defines thin, medium, and thick as keyword values that browsers interpret consistently. Typically, thin is 1px, medium is 3px, and thick is 5px, but this can vary slightly by browser.

Creating Custom Border Width Variables

You can provide completely custom border width values with specific pixel measurements:

import { styleframe } from 'styleframe';
import { useBorderWidth } from '@styleframe/theme';

const s = styleframe();

const {
    borderWidth,
    borderWidthHairline,
    borderWidthBold,
    borderWidthHeavy
} = useBorderWidth(s, {
    default: '1px',
    hairline: '0.5px',
    bold: '2px',
    heavy: '4px'
});

export default s;

Updating the Default Border Width Variable

You can override the default border width value after creating it by using variable():

import { styleframe } from 'styleframe';
import { useBorderWidth } from '@styleframe/theme';

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

const { borderWidth } = useBorderWidth(s);

// Override the default border width
variable(borderWidth, '2px');

export default s;

Extending the Default Border Width Values

You can customize which width is used as the default while keeping all other standard widths. Use the @ prefix to reference another key in the values object:

import { styleframe } from 'styleframe';
import { useBorderWidth, defaultBorderWidthValues } from '@styleframe/theme';

const s = styleframe();

const { borderWidth } = useBorderWidth(s, {
    ...defaultBorderWidthValues,
    default: '@medium'
});

export default s;
Pro tip: You can mix standard CSS keywords with custom pixel values by spreading defaultBorderWidthValues and adding your own custom widths. This gives you the flexibility of both approaches.

useBorderColor

The useBorderColor() function creates a set of border color variables that reference your base color system. This provides semantic separation between general colors and colors specifically intended for borders.

import { styleframe } from 'styleframe';
import { useColor, useBorderColor } from '@styleframe/theme';

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

// Define base colors
const { colorGray, colorPrimary, colorSuccess, colorDanger } = useColor(s, {
    gray: '#6b7280',
    primary: '#3b82f6',
    success: '#10b981',
    danger: '#ef4444',
} as const);

// Create border color variables
const {
    borderColor,
    borderColorPrimary,
    borderColorSuccess,
    borderColorDanger,
} = useBorderColor(s, {
    default: ref(colorGray),
    primary: ref(colorPrimary),
    success: ref(colorSuccess),
    danger: ref(colorDanger),
} as const);

export default s;

Each key in the object becomes a border color variable with the prefix border-color--, and the export name is automatically converted to camelCase (e.g., defaultborderColor, primaryborderColorPrimary).

Pro tip: Using useBorderColor() instead of directly referencing color variables makes your intent explicit and allows you to easily adjust border colors independently from your base color palette. For example, you might want borders to be lighter or more desaturated than the base colors.

Creating Border Color Lightness Variants

You can combine useBorderColor() with color manipulation composables to create sophisticated border color systems:

import { styleframe } from 'styleframe';
import { useColor, useColorLightness, useBorderColor } from '@styleframe/theme';

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

// Base color
const { colorGray } = useColor(s, { gray: '#6b7280' } as const);

// Create lightness variants
const { colorGray300, colorGray500, colorGray700 } = useColorLightness(s, colorGray, {
    300: 35,
    500: 55,
    700: 82,
} as const);

// Create semantic border colors
const {
    borderColor,
    borderColorLighter,
    borderColorDarker,
} = useBorderColor(s, {
    default: ref(colorGray500),
    lighter: ref(colorGray300),
    darker: ref(colorGray700),
} as const);

export default s;

Creating Border Color State Variants

Create border colors for different interactive states:

import { styleframe } from 'styleframe';
import { useBorderStyle, useBorderWidth, useColor, useBorderColor } from '@styleframe/theme';

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

const { borderStyle } = useBorderStyle(s);
const { borderWidth } = useBorderWidth(s);

// Define base colors for different states
const { colorGray, colorBlue, colorRed, colorGreen } = useColor(s, {
    gray: '#d1d5db',
    blue: '#3b82f6',
    red: '#ef4444',
    green: '#10b981',
} as const);

// Create state-based border colors
const {
    borderColor,
    borderColorHover,
    borderColorFocus,
    borderColorError,
    borderColorSuccess,
} = useBorderColor(s, {
    default: ref(colorGray),
    hover: ref(colorBlue),
    focus: ref(colorBlue),
    error: ref(colorRed),
    success: ref(colorGreen),
} as const);

// Apply state-based borders
selector('.input', {
    border: css`${ref(borderWidth)} ${ref(borderStyle)} ${ref(borderColor)}`,
    transition: 'border-color 0.2s ease',
    '&:hover': {
        borderColor: ref(borderColorHover),
    },
    '&:focus': {
        borderColor: ref(borderColorFocus),
        outline: 'none',
    },
    '&.error': {
        borderColor: ref(borderColorError),
    },
    '&.success': {
        borderColor: ref(borderColorSuccess),
    },
});

export default s;

Updating the Default Border Color Variable in Themes

Create borders that automatically adapt to light and dark themes:

import { styleframe } from 'styleframe';
import { useBorderStyle, useBorderWidth, useColor, useColorLightness, useBorderColor } from '@styleframe/theme';

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

const { borderStyle } = useBorderStyle(s);
const { borderWidth } = useBorderWidth(s);

// Base color
const { colorGray } = useColor(s, { gray: '#6b7280' } as const);

// Create lightness variants
const { colorGray300, colorGray700 } = useColorLightness(s, colorGray, {
    300: 35,
    700: 82,
} as const);

const { borderColor } = useBorderColor(s, colorGray, {
    default: ref(colorGray300),
} as const);

theme('dark', (ctx) => {
    // Override default border color in dark theme
    ctx.variable(borderColor, ref(colorGray700));
});

// Use theme-aware border
selector('.card', {
    border: css`${ref(borderWidth)} ${ref(borderStyle)} ${ref(borderColor)}`,
});

export default s;

Using Border Variables

Here's how to combine all three border composables to create a comprehensive border system:

import { styleframe } from 'styleframe';
import { useBorderStyle, useBorderWidth, useColor, useBorderColor } from '@styleframe/theme';

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

// Setup border styles and widths
const { borderStyle, borderStyleDashed } = useBorderStyle(s);
const { borderWidth, borderWidthMedium } = useBorderWidth(s);

// Setup base colors
const { colorGray, colorPrimary, colorSuccess, colorWarning, colorDanger } = useColor(s, {
    gray: '#d1d5db',
    primary: '#3b82f6',
    success: '#10b981',
    warning: '#f59e0b',
    danger: '#ef4444',
} as const);

// Setup border colors
const {
    borderColor,
    borderColorPrimary,
    borderColorSuccess,
    borderColorWarning,
    borderColorDanger,
} = useBorderColor(s, {
    default: ref(colorGray),
    primary: ref(colorPrimary),
    success: ref(colorSuccess),
    warning: ref(colorWarning),
    danger: ref(colorDanger),
} as const);

// Use border variables in components
selector('.card', {
    border: css`${ref(borderWidth)} ${ref(borderStyle)} ${ref(borderColor)}`,
});

selector('.input', {
    border: css`${ref(borderWidth)} ${ref(borderStyle)} ${ref(borderColor)}`,
    '&:focus': {
        borderColor: ref(borderColorPrimary),
    },
});

selector('.alert', {
    border: css`${ref(borderWidth)} ${ref(borderStyle)} ${ref(borderColor)}`,
    '&.success': {
        borderColor: ref(borderColorSuccess),
        borderLeftWidth: ref(borderWidthMedium),
    },
    '&.warning': {
        borderColor: ref(borderColorWarning),
        borderLeftWidth: ref(borderWidthMedium),
    },
    '&.danger': {
        borderColor: ref(borderColorDanger),
        borderLeftWidth: ref(borderWidthMedium),
    },
});

export default s;

Best Practices

  • Use useBorderColor() for semantic separation: Create border-specific color variables instead of directly referencing color variables. This gives you flexibility to adjust border colors independently.
  • Leverage default variables: Use the --border-style, --border-width, and --border-color variables for consistency across your application.
  • Create complete border variables: Combine width, style, and color into single variables (like --border) for frequently used border combinations.
  • Consider transparency: Use alpha channel adjustments on border colors for subtle borders that work on any background.
  • Keep it simple: Most applications only need 2-3 border widths and primarily use solid and dashed styles.
  • Test accessibility: Ensure borders provide sufficient contrast and aren't the only indicator of interactive states.
  • Plan for themes: Use useBorderColor() together with theme() to create theme-aware border colors that automatically adapt to light/dark modes.
Good to know: The useBorderColor() composable accepts any value, not just color references. You can pass direct color values, but using references from useColor() is recommended for consistency and maintainability.

FAQ