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.
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
});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
});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'
}
}
};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'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-/);
});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];/**
* 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>>;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;
};