Skip to content

Cross-Platform Usage

Sparkle’s theme system is designed to work seamlessly across web and React Native platforms, providing a unified design language while respecting platform-specific constraints.

On web platforms, Sparkle automatically converts design tokens to CSS custom properties:

/* Auto-generated CSS custom properties */
:root {
--colors-primary-500: #3b82f6;
--colors-secondary-500: #64748b;
--spacing-md: 1rem;
--typography-fontSize-base: 1rem;
--borderRadius-lg: 0.5rem;
}
/* Dark theme overrides */
[data-theme="dark"] {
--colors-background-primary: #1f2937;
--colors-text-primary: #f9fafb;
}

Access theme tokens in React components:

import { useThemeTokens } from '@sparkle/theme'
function WebButton() {
const tokens = useThemeTokens()
const styles = {
backgroundColor: `var(--colors-primary-500)`,
color: `var(--colors-white)`,
padding: `var(--spacing-sm) var(--spacing-md)`,
borderRadius: `var(--borderRadius-md)`,
fontSize: `var(--typography-fontSize-base)`,
}
return <button style={styles}>Web Button</button>
}

Use with popular CSS-in-JS libraries:

import { useThemeTokens } from '@sparkle/theme'
import styled from 'styled-components'
const StyledButton = styled.button`
background-color: var(--colors-primary-500);
color: var(--colors-white);
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--borderRadius-md);
font-size: var(--typography-fontSize-base);
&:hover {
background-color: var(--colors-primary-600);
}
`

For React Native, tokens are converted to StyleSheet-compatible values:

import { useNativeThemeTokens } from '@sparkle/theme'
import { StyleSheet } from 'react-native'
function NativeButton() {
const tokens = useNativeThemeTokens()
const styles = StyleSheet.create({
button: {
backgroundColor: tokens.colors.primary[500], // '#3b82f6'
paddingVertical: tokens.spacing.sm, // 8
paddingHorizontal: tokens.spacing.md, // 16
borderRadius: tokens.borderRadius.md, // 6
},
text: {
color: tokens.colors.white, // '#ffffff'
fontSize: tokens.typography.fontSize.base, // 16
fontWeight: tokens.typography.fontWeight.medium, // '500'
}
})
return (
<TouchableOpacity style={styles.button}>
<Text style={styles.text}>Native Button</Text>
</TouchableOpacity>
)
}
import { NativeThemeProvider } from '@sparkle/theme'
function App() {
return (
<NativeThemeProvider theme="light">
<NavigationContainer>
<YourAppScreens />
</NavigationContainer>
</NativeThemeProvider>
)
}

Sparkle automatically converts token values between platforms:

Token TypeWeb ValueReact Native Value
Colors#3b82f6#3b82f6
Spacing1rem16px16
Font Size1rem16px16
Font Weight500'500'
Border Radius0.5rem8px8

Create custom token transformers for specific needs:

import { createTokenTransformer } from '@sparkle/theme'
const customTransformer = createTokenTransformer({
// Convert rem values to dp for Android
spacing: (value) => {
if (Platform.OS === 'android') {
return Number.parseFloat(value) * 16 // Convert rem to dp
}
return Number.parseFloat(value) * 16 // Default to pixels
},
// Platform-specific font family mapping
fontFamily: (value) => {
const fontMap = {
'Inter': Platform.select({
ios: 'Inter',
android: 'Inter-Regular',
web: 'Inter, system-ui, sans-serif'
})
}
return fontMap[value] || value
}
})

Use CSS media queries with Sparkle tokens:

.container {
padding: var(--spacing-sm);
}
@media (min-width: 768px) {
.container {
padding: var(--spacing-md);
}
}
@media (min-width: 1024px) {
.container {
padding: var(--spacing-lg);
}
}

Use Dimensions API with theme tokens:

import { useNativeThemeTokens } from '@sparkle/theme'
import { Dimensions } from 'react-native'
function ResponsiveComponent() {
const tokens = useNativeThemeTokens()
const { width } = Dimensions.get('window')
const isTablet = width >= 768
const styles = StyleSheet.create({
container: {
padding: isTablet ? tokens.spacing.lg : tokens.spacing.md,
fontSize: isTablet ? tokens.typography.fontSize.lg : tokens.typography.fontSize.base,
}
})
return <View style={styles.container} />
}

Define platform-specific token values:

import { Platform } from 'react-native'
const platformTheme = {
typography: {
fontFamily: {
sans: Platform.select({
ios: 'San Francisco',
android: 'Roboto',
web: 'Inter, system-ui, sans-serif'
})
}
},
spacing: {
// iOS uses more generous spacing
md: Platform.select({
ios: 20,
android: 16,
web: '1rem'
})
}
}

Handle platform differences in components:

import { useNativeThemeTokens, useThemeTokens } from '@sparkle/theme'
import { Platform } from 'react-native'
function CrossPlatformButton({ children, ...props }) {
if (Platform.OS === 'web') {
const tokens = useThemeTokens()
return (
<button
style={{
backgroundColor: `var(--colors-primary-500)`,
padding: `var(--spacing-sm) var(--spacing-md)`
}}
{...props}
>
{children}
</button>
)
}
const tokens = useNativeThemeTokens()
return (
<TouchableOpacity
style={{
backgroundColor: tokens.colors.primary[500],
paddingVertical: tokens.spacing.sm,
paddingHorizontal: tokens.spacing.md
}}
{...props}
>
<Text>{children}</Text>
</TouchableOpacity>
)
}
  1. CSS Custom Properties: Fast runtime theme switching
  2. CSS-in-JS Optimization: Use static styles when possible
  3. Bundle Splitting: Load themes on demand
  4. Caching: Cache computed styles
// Optimized web component
const OptimizedButton = memo(styled.button`
/* Static styles - no runtime computation */
background-color: var(--colors-primary-500);
transition: background-color 0.2s ease;
&:hover {
background-color: var(--colors-primary-600);
}
`)
  1. StyleSheet.create: Use for better performance
  2. Static Styles: Compute styles outside render
  3. Memoization: Cache expensive calculations
  4. Avoid Inline Styles: Use StyleSheet objects
// Optimized React Native component
const styles = StyleSheet.create({
button: {
backgroundColor: '#3b82f6', // Static value for performance
paddingVertical: 8,
paddingHorizontal: 16,
}
})
const OptimizedButton = memo(({ children }) => (
<TouchableOpacity style={styles.button}>
<Text>{children}</Text>
</TouchableOpacity>
))

Test components across platforms with consistent tokens:

// Shared test component
export const TestButton = ({ platform = 'web' }) => {
if (platform === 'web') {
return <WebButton>Test Button</WebButton>
}
return <NativeButton>Test Button</NativeButton>
}
// Storybook stories
export default {
title: 'Cross-Platform/Button',
component: TestButton,
}
export const Web = {
args: { platform: 'web' }
}
export const Native = {
args: { platform: 'native' }
}

Verify tokens produce consistent results:

import { nativeTokens, webTokens } from '@sparkle/theme'
describe('Token Consistency', () => {
test('color values match across platforms', () => {
expect(webTokens.colors.primary[500]).toBe('#3b82f6')
expect(nativeTokens.colors.primary[500]).toBe('#3b82f6')
})
test('spacing converts correctly', () => {
expect(webTokens.spacing.md).toBe('1rem')
expect(nativeTokens.spacing.md).toBe(16)
})
})

Gradually migrate to Sparkle themes:

/* Phase 1: Use CSS custom properties alongside existing styles */
.legacy-button {
background: var(--colors-primary-500, #blue); /* Fallback */
padding: var(--spacing-md, 16px);
}
/* Phase 2: Full Sparkle integration */
.sparkle-button {
background: var(--colors-primary-500);
padding: var(--spacing-md);
}

Migrate StyleSheet objects:

// Before: Hard-coded values
const oldStyles = StyleSheet.create({
button: {
backgroundColor: '#3b82f6',
padding: 16,
}
})
// After: Sparkle tokens
const newStyles = StyleSheet.create({
button: {
backgroundColor: tokens.colors.primary[500],
padding: tokens.spacing.md,
}
})