or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdfont-animation.mdindex.mdserver-rendering.mdstyle-sets.mdstyling.md
tile.json

style-sets.mddocs/

Style Sets and Concatenation

Functions for managing multiple related styles as sets, concatenating style objects, and working with component style hierarchies. Style sets enable you to define multiple CSS classes at once while maintaining relationships and ensuring proper ordering.

Capabilities

mergeStyleSets Function

Creates a map of CSS class names from a style set object. Each property in the style set becomes a CSS class name, ensuring proper ordering when multiple style sets are merged.

/**
 * Takes in one or more style set objects and produces a map of class names
 * @param styleSets - One or more style sets to be merged
 * @returns Processed style set with class name strings
 */
function mergeStyleSets(...styleSets: Array<IStyleSet | undefined | false | null>): IProcessedStyleSet<any>;

Usage Examples:

import { mergeStyleSets } from '@uifabric/merge-styles';

// Basic style set
const classNames = mergeStyleSets({
  root: {
    background: 'white',
    padding: '20px',
    borderRadius: '4px'
  },
  title: {
    fontSize: '24px',
    fontWeight: 'bold',
    marginBottom: '10px'
  },
  content: {
    fontSize: '16px',
    lineHeight: '1.5'
  }
});

// Results in: { root: 'root-0', title: 'title-1', content: 'content-2' }

// Usage in React
function Card({ title, children }) {
  return (
    <div className={classNames.root}>
      <h2 className={classNames.title}>{title}</h2>
      <div className={classNames.content}>{children}</div>
    </div>
  );
}

Merging Multiple Style Sets:

// Base styles
const baseStyles = {
  root: { padding: '10px' },
  button: { border: 'none' }
};

// Theme styles
const themeStyles = {
  root: { background: 'lightblue' },
  button: { background: 'blue', color: 'white' }
};

// Conditional styles
const conditionalStyles = isLarge && {
  root: { padding: '20px' },
  button: { fontSize: '18px' }
};

const classNames = mergeStyleSets(baseStyles, themeStyles, conditionalStyles);

mergeCssSets Function

Lower-level function for merging style sets with custom options. Provides more control over the CSS generation process.

/**
 * Merges style sets with custom processing options
 * @param styleSets - Array of style sets to merge
 * @param options - Optional configuration for style processing
 * @returns Processed style set with class name strings
 */
function mergeCssSets(
  styleSets: Array<IStyleSet | undefined | false | null>,
  options?: IStyleOptions
): IProcessedStyleSet<any>;

Usage Examples:

import { mergeCssSets } from '@uifabric/merge-styles';

const classNames = mergeCssSets([
  {
    root: { marginLeft: '10px' },
    button: { textAlign: 'left' }
  }
], {
  rtl: true // Enable RTL transformations
});

concatStyleSets Function

Combines multiple style sets without registering CSS classes. Useful for preparing styles before final processing or when you need to merge style sets conditionally.

/**
 * Combine style sets without registering CSS classes
 * @param styleSets - One or more style sets to concatenate
 * @returns Concatenated style set (not processed into class names)
 */
function concatStyleSets(...styleSets: (IStyleSet | false | null | undefined)[]): IConcatenatedStyleSet<any>;

Usage Examples:

import { concatStyleSets, mergeStyleSets } from '@uifabric/merge-styles';

// Prepare styles without generating classes
const baseStyles = { root: { padding: '10px' } };
const themeStyles = { root: { background: 'blue' } };

// Concatenate first
const combinedStyles = concatStyleSets(baseStyles, themeStyles);

// Then generate classes when needed
const classNames = mergeStyleSets(combinedStyles);

concatStyleSetsWithProps Function

Concatenates style sets while resolving functional style sets using provided props. Essential for components that accept style functions based on props.

/**
 * Concatenates style sets and resolves functional sets using props
 * @param styleProps - Props used to resolve functional style sets
 * @param allStyles - Style sets, which can be functions or objects
 * @returns Merged and resolved style set
 */
function concatStyleSetsWithProps<TStyleProps, TStyleSet extends IStyleSet<TStyleSet>>(
  styleProps: TStyleProps,
  ...allStyles: (IStyleFunctionOrObject<TStyleProps, TStyleSet> | undefined)[]
): DeepPartial<TStyleSet>;

Usage Examples:

import { concatStyleSetsWithProps, mergeStyleSets } from '@uifabric/merge-styles';

interface ButtonProps {
  size: 'small' | 'large';
  variant: 'primary' | 'secondary';
}

// Style functions based on props
const buttonStyles = (props: ButtonProps) => ({
  root: {
    padding: props.size === 'large' ? '12px 24px' : '6px 12px',
    background: props.variant === 'primary' ? 'blue' : 'gray'
  }
});

const additionalStyles = (props: ButtonProps) => ({
  root: {
    fontSize: props.size === 'large' ? '16px' : '14px'
  }
});

// Resolve styles with props
const resolvedStyles = concatStyleSetsWithProps(
  { size: 'large', variant: 'primary' },
  buttonStyles,
  additionalStyles
);

// Generate final class names
const classNames = mergeStyleSets(resolvedStyles);

SubComponent Styles

Style sets support sub-component styling through the special subComponentStyles property, enabling hierarchical style management.

// Parent component style set with sub-component styles
const parentStyles = mergeStyleSets({
  root: { 
    display: 'flex',
    flexDirection: 'column'
  },
  
  // Define styles for child components
  subComponentStyles: {
    // These become style functions
    childButton: (props) => ({
      root: {
        background: props.primary ? 'blue' : 'gray'
      }
    }),
    
    childInput: {
      root: {
        border: '1px solid #ccc',
        padding: '8px'
      }
    }
  }
});

// Access sub-component styles
const childButtonStyles = parentStyles.subComponentStyles.childButton({ primary: true });

Style Set Types

type IStyleSet<TStyleSet extends IStyleSet<TStyleSet> = { [key: string]: any }> = {
  [P in keyof Omit<TStyleSet, 'subComponentStyles'>]: IStyle;
} & {
  subComponentStyles?: { 
    [P in keyof TStyleSet['subComponentStyles']]: IStyleFunctionOrObject<any, any> 
  };
};

type IConcatenatedStyleSet<TStyleSet extends IStyleSet<TStyleSet>> = {
  [P in keyof Omit<TStyleSet, 'subComponentStyles'>]: IStyle;
} & {
  subComponentStyles?: { 
    [P in keyof TStyleSet['subComponentStyles']]: IStyleFunction<any, any> 
  };
};

type IProcessedStyleSet<TStyleSet extends IStyleSet<TStyleSet>> = {
  [P in keyof Omit<TStyleSet, 'subComponentStyles'>]: string;
} & {
  subComponentStyles: {
    [P in keyof TStyleSet['subComponentStyles']]: __MapToFunctionType<
      TStyleSet['subComponentStyles'] extends infer J ? (P extends keyof J ? J[P] : never) : never
    >;
  };
};

type IStyleFunction<TStylesProps, TStyleSet extends IStyleSet<TStyleSet>> = (
  props: TStylesProps
) => DeepPartial<TStyleSet>;

type IStyleFunctionOrObject<TStylesProps, TStyleSet extends IStyleSet<TStyleSet>> =
  | IStyleFunction<TStylesProps, TStyleSet>
  | DeepPartial<TStyleSet>;

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

Best Practices

Organizing Component Styles:

// Recommended pattern: separate file for styles
// MyComponent.styles.ts
export const getClassNames = (props: MyComponentProps) => {
  return mergeStyleSets({
    root: [
      'MyComponent-root', // Static class name for external targeting
      {
        display: 'flex',
        padding: '10px'
      },
      props.isActive && {
        background: 'lightblue'
      }
    ],
    
    button: [
      'MyComponent-button',
      {
        border: 'none',
        borderRadius: '4px'
      }
    ]
  });
};

// MyComponent.tsx
import { getClassNames } from './MyComponent.styles';

export const MyComponent = (props: MyComponentProps) => {
  const classNames = getClassNames(props);
  
  return (
    <div className={classNames.root}>
      <button className={classNames.button}>Click me</button>
    </div>
  );
};

Performance Optimization:

import { memoizeFunction } from '@uifabric/utilities';

// Memoize style generation for performance
export const getClassNames = memoizeFunction((
  isActive: boolean,
  size: 'small' | 'large'
) => {
  return mergeStyleSets({
    root: [
      { padding: size === 'large' ? '20px' : '10px' },
      isActive && { background: 'lightblue' }
    ]
  });
});