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

configuration.mddocs/

Configuration and State Management

Functions and classes for configuring the library's behavior, managing RTL state, and controlling CSS injection. These utilities provide fine-grained control over how merge-styles processes and injects CSS rules.

Capabilities

RTL State Management

Functions for managing right-to-left (RTL) text direction support, which automatically transforms CSS properties for international applications.

/**
 * Sets the current RTL (right-to-left) mode
 * @param isRTL - True to enable RTL transformations, false to disable
 */
function setRTL(isRTL: boolean): void;

Usage Examples:

import { setRTL, mergeStyles } from '@uifabric/merge-styles';

// Enable RTL mode
setRTL(true);

// Styles will now be automatically flipped
const rtlStyles = mergeStyles({
  marginLeft: '10px',    // Becomes marginRight: '10px'
  paddingRight: '5px',   // Becomes paddingLeft: '5px'
  textAlign: 'left',     // Becomes textAlign: 'right'
  borderRadius: '4px 0 0 4px'  // Becomes '0 4px 4px 0'
});

// Disable RTL mode
setRTL(false);

Application-Level RTL Management:

// You can manually set RTL based on user preference or locale
const userLocale = 'ar-SA'; // Arabic locale
const isRTLLocale = ['ar', 'he', 'fa', 'ur'].some(lang => 
  userLocale.startsWith(lang)
);

setRTL(isRTLLocale);

// Or detect from HTML document direction
const isDocumentRTL = document.documentElement.dir === 'rtl';
setRTL(isDocumentRTL);

Preventing RTL Transformations:

// Use @noflip directive to prevent specific properties from being flipped
const mixedDirectionStyles = mergeStyles({
  marginLeft: '10px',           // Will be flipped in RTL
  paddingLeft: '5px @noflip'    // Won't be flipped in RTL
});

Stylesheet Management

The Stylesheet class provides low-level control over CSS rule generation, injection, and caching.

/**
 * Singleton class managing CSS rule injection and caching
 */
class Stylesheet {
  /** Get the global Stylesheet instance */
  static getInstance(): Stylesheet;
  
  /** Configure stylesheet behavior */
  setConfig(config: IStyleSheetConfig): void;
  
  /** Insert a CSS rule into the stylesheet */
  insertRule(rule: string, preserve?: boolean): void;
  
  /** Get all generated CSS rules as a string */
  getRules(forceUpdate?: boolean): string;
  
  /** Reset the stylesheet, clearing all rules and cache */
  reset(): void;
  
  /** Generate a unique class name */
  getClassName(displayName?: string): string;
  
  /** Cache a class name with its associated styles */
  cacheClassName(className: string, key: string, args: any[], rules: any[]): void;
}

Usage Examples:

import { Stylesheet, InjectionMode } from '@uifabric/merge-styles';

// Get the global stylesheet instance
const stylesheet = Stylesheet.getInstance();

// Configure stylesheet behavior
stylesheet.setConfig({
  injectionMode: InjectionMode.insertNode, // How to inject CSS
  defaultPrefix: 'myapp',                  // Default class name prefix
  namespace: 'myapp',                      // Namespace for isolation
  cspSettings: { nonce: 'random-nonce' }   // Content Security Policy nonce
});

// Manually insert custom CSS rules
stylesheet.insertRule('.custom-rule { color: red; }');

// Get all generated CSS (useful for server-side rendering)
const allCSS = stylesheet.getRules();

// Reset stylesheet (useful for testing or server-side rendering)
stylesheet.reset();

CSS Injection Modes:

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

// Different ways to inject CSS into the document
const injectionModes = {
  // Don't inject CSS (useful for server-side rendering)
  none: InjectionMode.none,
  
  // Use insertRule API (default, most performant)
  insertNode: InjectionMode.insertNode,
  
  // Use appendChild (compatibility mode)
  appendChild: InjectionMode.appendChild
};

// Configure injection mode
stylesheet.setConfig({
  injectionMode: InjectionMode.none // For server-side rendering
});

Content Security Policy (CSP) Support

Configure CSP settings for secure applications that require nonces for style injection.

// Set CSP nonce for style injection
stylesheet.setConfig({
  cspSettings: {
    nonce: 'your-csp-nonce-here'
  }
});

// Alternative: Global configuration (must be set before any styles are generated)
window.FabricConfig = {
  mergeStyles: {
    cspSettings: {
      nonce: 'your-csp-nonce-here'
    }
  }
};

Custom Class Name Generation

Control how CSS class names are generated and prefixed.

// Configure default prefix
stylesheet.setConfig({
  defaultPrefix: 'mycomponent' // Classes become: .mycomponent-0, .mycomponent-1, etc.
});

// Use namespace for isolation
stylesheet.setConfig({
  namespace: 'myapp' // Classes become: .myapp-css-0, .myapp-css-1, etc.
});

// Generate custom class names
const customClassName = stylesheet.getClassName('MyButton');
// Returns something like: 'MyButton-0'

Advanced Configuration Patterns

Environment-Specific Configuration:

import { Stylesheet, InjectionMode } from '@uifabric/merge-styles';

const isServer = typeof document === 'undefined';
const isDevelopment = process.env.NODE_ENV === 'development';

// Configure based on environment
Stylesheet.getInstance().setConfig({
  // Server-side rendering: don't inject CSS
  injectionMode: isServer ? InjectionMode.none : InjectionMode.insertNode,
  
  // Development: use descriptive prefixes
  defaultPrefix: isDevelopment ? 'dev' : 'css',
  
  // Production: use shorter namespace
  namespace: isDevelopment ? 'myapp-dev' : 'app'
});

Multi-Tenant Applications:

// Configure for tenant isolation
const configureTenant = (tenantId: string) => {
  Stylesheet.getInstance().setConfig({
    namespace: `tenant-${tenantId}`,
    defaultPrefix: tenantId
  });
};

// Switch tenants
configureTenant('acme-corp');
// Classes become: .tenant-acme-corp-css-0, .acme-corp-1, etc.

configureTenant('globodyne');
// Classes become: .tenant-globodyne-css-0, .globodyne-1, etc.

Testing Configuration:

// Test setup - reset before each test
beforeEach(() => {
  const stylesheet = Stylesheet.getInstance();
  stylesheet.reset();
  stylesheet.setConfig({
    injectionMode: InjectionMode.none, // Don't inject in tests
    defaultPrefix: 'test'
  });
});

// Get generated CSS for testing
it('should generate correct styles', () => {
  const className = mergeStyles({ color: 'red' });
  const css = Stylesheet.getInstance().getRules();
  
  expect(css).toContain('color: red');
  expect(className).toMatch(/^test-/);
});

Configuration Types

interface IStyleOptions {
  /** Enable RTL (right-to-left) transformations */
  rtl?: boolean;
  
  /** Multiply CSS specificity by this factor */
  specificityMultiplier?: number;
}

interface IStyleSheetConfig {
  /** How to inject CSS rules into the document */
  injectionMode?: InjectionMode;
  
  /** Default class name prefix */
  defaultPrefix?: string;
  
  /** Namespace for CSS class isolation */
  namespace?: string;
  
  /** Content Security Policy settings */
  cspSettings?: ICSPSettings;
}

interface ICSPSettings {
  /** Nonce value for CSP compliance */
  nonce?: string;
}

const InjectionMode = {
  /** Don't inject CSS (for server-side rendering) */
  none: 0 as 0,
  
  /** Inject using insertRule API (default) */
  insertNode: 1 as 1,
  
  /** Inject using appendChild (compatibility mode) */
  appendChild: 2 as 2
};

type InjectionMode = typeof InjectionMode[keyof typeof InjectionMode];

Utility Functions and Classes

/**
 * Extracts class names and style objects from mixed style arguments
 */
function extractStyleParts(args: IStyle[]): { classes: string[]; objects: {}[] };

/**
 * Converts style objects to CSS class names
 */
function styleToClassName(options: IStyleOptions, ...objects: {}[]): string;

/**
 * Type that makes all properties optional recursively
 */
type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends (infer U)[] ? DeepPartial<U>[] : T[P] extends object ? DeepPartial<T[P]> : T[P];
};

/**
 * Type that filters out function properties
 */
type ObjectOnly<TArg> = TArg extends {} ? TArg : {};

/**
 * Type that omits specified keys from a type
 */
type Omit<U, K extends keyof U> = Pick<U, Diff<keyof U, K>>;

Integration Patterns

React Hook for RTL:

import { useEffect, useState } from 'react';
import { setRTL } from '@uifabric/merge-styles';

// Custom hook for RTL management
export const useRTL = (initialRTL = false) => {
  const [isRTL, setIsRTLState] = useState(initialRTL);
  
  const toggleRTL = (rtl: boolean) => {
    setRTL(rtl);
    setIsRTLState(rtl);
  };
  
  return { isRTL, setRTL: toggleRTL };
};

// Usage in component
const MyComponent = () => {
  const { isRTL, setRTL } = useRTL();
  
  return (
    <div>
      <button onClick={() => setRTL(!isRTL)}>
        Toggle RTL ({isRTL ? 'ON' : 'OFF'})
      </button>
    </div>
  );
};

Theme Provider with RTL:

import { createContext, useContext, useEffect } from 'react';
import { setRTL } from '@uifabric/merge-styles';

interface ThemeContextValue {
  locale: string;
  isRTL: boolean;
  setLocale: (locale: string) => void;
}

const ThemeContext = createContext<ThemeContextValue | null>(null);

export const ThemeProvider = ({ children }) => {
  const [locale, setLocaleState] = useState('en-US');
  
  const isRTL = ['ar', 'he', 'fa', 'ur'].some(lang => 
    locale.startsWith(lang)
  );
  
  useEffect(() => {
    setRTL(isRTL);
  }, [isRTL]);
  
  const setLocale = (newLocale: string) => {
    setLocaleState(newLocale);
  };
  
  return (
    <ThemeContext.Provider value={{ locale, isRTL, setLocale }}>
      {children}
    </ThemeContext.Provider>
  );
};

export const useTheme = () => {
  const context = useContext(ThemeContext);
  if (!context) {
    throw new Error('useTheme must be used within ThemeProvider');
  }
  return context;
};