Universal style library for React and React Native with cross-platform support
—
Helper functions for style processing, event handling, platform detection, and component utilities.
Utilities for composing and managing event handlers across platforms.
/**
* Compose multiple event handlers into a single function
* @param original - Original event handler
* @param next - Next event handler to compose
* @returns Composed event handler that calls both functions
*/
function composeEventHandlers<T extends Function>(
original?: T,
next?: T
): T;Usage Examples:
import { composeEventHandlers, styled, View } from "@tamagui/core";
function ComposedEvents() {
const handlePress1 = () => console.log('First handler');
const handlePress2 = () => console.log('Second handler');
const composedHandler = composeEventHandlers(handlePress1, handlePress2);
return (
<View onPress={composedHandler}>
<Text>Press me - both handlers will fire</Text>
</View>
);
}
// Using in styled components
const InteractiveView = styled(View, {
backgroundColor: '$background',
padding: '$4',
variants: {
interactive: {
true: {
cursor: 'pointer',
},
},
},
});
function InteractiveComponent({ onPress, onCustomEvent }) {
const handlePress = composeEventHandlers(
onPress,
(event) => {
// Custom press handling
console.log('Custom press handling');
onCustomEvent?.(event);
}
);
return (
<InteractiveView onPress={handlePress} interactive>
<Text>Interactive element</Text>
</InteractiveView>
);
}Advanced style processing and splitting utilities for optimized rendering.
/**
* Split component props into style and non-style properties
* @param props - Component props to split
* @param staticConfig - Component static configuration
* @param theme - Current theme context
* @param state - Component state (hover, press, focus)
* @param options - Processing options
* @returns Split styles and properties
*/
function getSplitStyles<T>(
props: T,
staticConfig: StaticConfig,
theme: Theme,
state: ComponentState,
options?: GetStylesOptions
): SplitStyles;
/**
* Expand shorthand CSS properties to their full forms
* @param styles - Style object with potential shorthands
* @returns Style object with expanded properties
*/
function expandStyles(styles: StyleObject): StyleObject;
/**
* Get expanded shorthand properties mapping
* @param styles - Style object to process
* @returns Mapping of shorthand to expanded properties
*/
function getExpandedShorthands(styles: StyleObject): Record<string, string[]>;
/**
* Generate atomic CSS classes and rules
* @param styles - Style object to convert
* @returns Object with CSS class names and rule definitions
*/
function getCSSStylesAtomic(styles: StyleObject): {
classNames: string;
rules: string[];
};
interface SplitStyles {
/** Non-media style properties */
style: StyleObject;
/** Generated CSS class names */
classNames: string;
/** Pseudo-state styles (hover, press, focus) */
pseudos: Record<string, StyleObject>;
/** Spacing-related styles */
space: StyleObject;
/** Whether media queries are present */
hasMedia: boolean;
}
interface GetStylesOptions {
/** Disable shorthand expansion */
disableExpandShorthands?: boolean;
/** How to resolve CSS variables */
resolveVariablesAs?: 'value' | 'variable' | 'auto';
}
interface ComponentState {
hover: boolean;
press: boolean;
focus: boolean;
}Usage Examples:
import { getSplitStyles, expandStyles } from "@tamagui/core";
// Style expansion example
const shorthandStyles = {
padding: 16,
margin: '8px 16px',
border: '1px solid red',
};
const expandedStyles = expandStyles(shorthandStyles);
// Result: {
// paddingTop: 16, paddingRight: 16, paddingBottom: 16, paddingLeft: 16,
// marginTop: '8px', marginRight: '16px', marginBottom: '8px', marginLeft: '16px',
// borderWidth: '1px', borderStyle: 'solid', borderColor: 'red'
// }
// Advanced component using style splitting
function CustomComponent(props) {
const theme = useTheme();
const [state, setState] = useState({ hover: false, press: false, focus: false });
const splitStyles = getSplitStyles(
props,
{ componentName: 'Custom' },
theme,
state
);
return (
<div
className={splitStyles.classNames}
style={splitStyles.style}
onMouseEnter={() => setState(s => ({ ...s, hover: true }))}
onMouseLeave={() => setState(s => ({ ...s, hover: false }))}
>
{props.children}
</div>
);
}Functions for normalizing and processing style values across platforms.
/**
* Normalize color values for cross-platform compatibility
* @param color - Color value in any supported format
* @returns Normalized color string
*/
function normalizeColor(color: any): string;
/**
* Normalize style values with property-specific processing
* @param value - Style value to normalize
* @param property - CSS property name for context
* @returns Normalized value appropriate for the property
*/
function normalizeValueWithProperty(value: any, property: string): any;
/**
* Normalize entire style object
* @param styles - Style object to normalize
* @returns Normalized style object
*/
function normalizeStyle(styles: StyleObject): StyleObject;Usage Examples:
import { normalizeColor, normalizeValueWithProperty } from "@tamagui/core";
// Color normalization
const color1 = normalizeColor('#ff0000'); // '#ff0000'
const color2 = normalizeColor('red'); // '#ff0000'
const color3 = normalizeColor('rgb(255,0,0)'); // '#ff0000'
// Value normalization by property
const width = normalizeValueWithProperty(100, 'width'); // '100px'
const fontSize = normalizeValueWithProperty(16, 'fontSize'); // 16
const margin = normalizeValueWithProperty('auto', 'margin'); // 'auto'
// Practical usage in components
function NormalizedButton({ color, size, ...props }) {
const normalizedColor = normalizeColor(color || '#007AFF');
const normalizedSize = normalizeValueWithProperty(size || 16, 'fontSize');
return (
<View
style={{
backgroundColor: normalizedColor,
fontSize: normalizedSize,
}}
{...props}
/>
);
}Utilities for working with component properties and variants.
/**
* Process component props through Tamagui's prop system
* @param props - Raw component props
* @param config - Component configuration
* @returns Processed props with resolved tokens and variants
*/
function useProps<T>(props: T, config?: ComponentConfig): T;
/**
* Merge multiple prop objects with proper precedence
* @param props - Array of prop objects to merge
* @returns Merged props object
*/
function mergeProps(...props: Record<string, any>[]): Record<string, any>;
/**
* Get extra configuration for component variants
* @param variants - Variant configuration
* @param props - Component props
* @returns Extra variant configuration
*/
function getVariantExtras(
variants: VariantsConfig,
props: Record<string, any>
): VariantExtras;
/**
* Map props to different names or transform values
* @param propMappings - Mapping configuration
* @returns Prop mapping function
*/
function propMapper(propMappings: PropMappings): (props: any) => any;
interface ComponentConfig {
variants?: VariantsConfig;
defaultVariants?: Record<string, any>;
accept?: Record<string, any>;
}
interface VariantExtras {
resolvedProps: Record<string, any>;
variantStyles: StyleObject;
defaultVariants: Record<string, any>;
}
interface PropMappings {
[propName: string]: string | ((value: any) => any);
}Utilities for detecting and validating Tamagui components.
/**
* Check if a value is a Tamagui component
* @param component - Component to check
* @returns True if component is a Tamagui component
*/
function isTamaguiComponent(component: any): component is TamaguiComponent;
/**
* Check if a React element is a Tamagui element
* @param element - Element to check
* @returns True if element is created by a Tamagui component
*/
function isTamaguiElement(element: any): element is TamaguiElement;
/**
* Make a component compatible with Tamagui theming
* @param component - Component to make themeable
* @param config - Theming configuration
* @returns Themeable component
*/
function themeable<T extends React.ComponentType<any>>(
component: T,
config?: ThemeableConfig
): T;
interface ThemeableConfig {
accept?: Record<string, any>;
isText?: boolean;
}Cross-platform detection constants for conditional behavior.
/** True when running on web platform */
declare const isWeb: boolean;
/** True when running on server (SSR) */
declare const isServer: boolean;
/** True when running on client */
declare const isClient: boolean;
/** True when running on Android platform */
declare const isAndroid: boolean;
/** True when running on iOS platform */
declare const isIos: boolean;
/** True when device supports touch */
declare const isTouchable: boolean;
/** True when web platform supports touch */
declare const isWebTouchable: boolean;
/**
* SSR-safe version of useLayoutEffect
* Uses useLayoutEffect on client, useEffect on server
*/
declare const useIsomorphicLayoutEffect: typeof React.useLayoutEffect;Usage Examples:
import {
isWeb,
isAndroid,
isIos,
isTouchable,
useIsomorphicLayoutEffect
} from "@tamagui/core";
function PlatformAwareComponent() {
useIsomorphicLayoutEffect(() => {
// Safe to use on both client and server
console.log('Layout effect');
}, []);
return (
<View style={{
// Platform-specific styles
...isWeb && { cursor: 'pointer' },
...isAndroid && { elevation: 4 },
...isIos && { shadowOpacity: 0.3 },
...isTouchable && { minHeight: 44 }, // Touch target size
}}>
<Text>
Platform: {
isWeb ? 'Web' :
isAndroid ? 'Android' :
isIos ? 'iOS' :
'Unknown'
}
</Text>
</View>
);
}Utilities for working with React contexts in styled components.
/**
* Create a styled context for component communication
* @param defaultValue - Default context value
* @returns Context provider and consumer
*/
function createStyledContext<T>(defaultValue: T): {
Provider: React.ComponentType<{ value: T; children: React.ReactNode }>;
useStyledContext: () => T;
};
/**
* Component-level context for sharing state
*/
declare const ComponentContext: React.Context<ComponentContextValue>;
/**
* Group context for coordinating related components
*/
declare const GroupContext: React.Context<GroupContextValue>;
interface ComponentContextValue {
disabled?: boolean;
size?: string;
variant?: string;
}
interface GroupContextValue {
name?: string;
disabled?: boolean;
orientation?: 'horizontal' | 'vertical';
}Development and debugging utilities.
/**
* Setup development mode features
* @param options - Development configuration
*/
function setupDev(options?: DevOptions): void;
interface DevOptions {
/** Enable verbose logging */
debug?: boolean;
/** Enable style visualizer */
visualizer?: boolean;
/** Custom debug configuration */
debugConfig?: DebugConfig;
}
interface DebugConfig {
/** Log style calculations */
logStyles?: boolean;
/** Log theme changes */
logThemes?: boolean;
/** Log media query changes */
logMedia?: boolean;
}// Custom hook combining multiple utilities
function useOptimizedComponent(props, config) {
const theme = useTheme();
const media = useMedia();
const processedProps = useProps(props, config);
const splitStyles = useMemo(() =>
getSplitStyles(processedProps, config, theme, { hover: false, press: false, focus: false }),
[processedProps, config, theme]
);
return {
...processedProps,
style: splitStyles.style,
className: splitStyles.classNames,
};
}// Creating custom style processing logic
function createCustomStyleProcessor(options: ProcessorOptions) {
return (styles: StyleObject) => {
const expanded = expandStyles(styles);
const normalized = normalizeStyle(expanded);
if (options.addPrefix) {
return Object.keys(normalized).reduce((acc, key) => {
acc[`${options.prefix}-${key}`] = normalized[key];
return acc;
}, {});
}
return normalized;
};
}interface StyleObject {
[key: string]: any;
}
interface StaticConfig {
componentName?: string;
variants?: VariantsConfig;
defaultVariants?: Record<string, any>;
accept?: Record<string, any>;
isText?: boolean;
isZStack?: boolean;
validStyles?: Record<string, boolean>;
}
interface VariantsConfig {
[variantName: string]: {
[variantValue: string]: StyleObject | (() => StyleObject);
};
}
interface Theme {
[key: string]: string | Variable;
}
interface Variable<T = any> {
key: string;
name: string;
val: T;
variable: string;
}Install with Tessl CLI
npx tessl i tessl/npm-tamagui--core