Theme
The styles system is based on a centralized theme that contains all configurations related to component styling. The theme serves as the single source of truth for colors, spacing, typography, and other design tokens.
Creating a Theme
To create a theme, use the createTheme
and validateTheme
functions:
import { createTheme, validateTheme } from '@codeleap/styles'
const theme = createTheme(
validateTheme(exampleConfig),
{
set: (name, value) => anyStorage.set(name, value),
get: (name) => anyStorage.get(name),
}
)
Parameters
createTheme
: Main function that creates the theme and registers it in the styles system. Returns the theme with additional functionalities.validateTheme
: Function that validates the passed configuration to ensure it's in the correct format.themePersistor
(optional): Second parameter ofcreateTheme
used to persist important theme information:set(name, value)
: Function to save dataget(name)
: Function to retrieve data
⚠️ Important: Since the styles system depends on theme creation, it's essential that the theme file is imported first in the application root.
Theme Configuration
Complete Structure
const themeConfig = {
// Application base colors
baseColors: {
primary: '#007AFF',
secondary: '#FF3B30',
// ...
},
// Default mode colors (usually light)
colors: lightModeColors,
// Alternative colors (dark mode, high contrast, etc.)
alternateColors: {
dark: darkModeColors,
highContrast: highContrastColors,
},
// Base value for spacing system
baseSpacing: 8,
// Border radius values
radius: {
none: 0,
small: 4,
medium: 8,
large: 12,
full: 9999,
},
// Stroke/border values
stroke: {
none: 0,
thin: 1,
medium: 2,
thick: 3,
},
// Component default sizes
size: {
small: 32,
default: 40,
large: 48,
xlarge: 56,
},
// Visual effects (shadows, etc.)
effects: {
elevated: {
shadowOffset: { width: 0, height: 2 },
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowRadius: 8,
shadowOpacity: 1,
elevation: 2,
},
floating: {
shadowOffset: { width: 0, height: 4 },
shadowColor: 'rgba(0, 0, 0, 0.15)',
shadowRadius: 12,
shadowOpacity: 1,
elevation: 4,
}
},
// Typography settings
typography: {
fonts: {
Inter: {
normal: {
'100': 'Inter-Thin',
'200': 'Inter-ExtraLight',
'300': 'Inter-Light',
'400': 'Inter-Regular',
'500': 'Inter-Medium',
'600': 'Inter-SemiBold',
'700': 'Inter-Bold',
'800': 'Inter-ExtraBold',
'900': 'Inter-Black',
},
italic: {
'400': 'Inter-RegularItalic',
'500': 'Inter-MediumItalic',
// ...
}
},
},
defaults: {
fontFamily: 'Inter',
fontWeight: '400',
fontStyle: 'normal',
fontSize: 16,
lineHeight: 24,
letterSpacing: 0,
},
},
// Application icons
icons: IconSet,
// Custom utility functions
presets: {
cardShadow: () => ({
shadowOffset: { width: 0, height: 2 },
shadowRadius: 8,
shadowOpacity: 0.1,
}),
buttonSize: (size: 'small' | 'medium' | 'large') => ({
height: size === 'small' ? 32 : size === 'medium' ? 40 : 48,
paddingHorizontal: size === 'small' ? 12 : size === 'medium' ? 16 : 20,
})
},
// Custom application values
values: {
headerHeight: 60,
tabBarHeight: 80,
iconSize: {
xs: 12,
sm: 16,
md: 20,
lg: 24,
xl: 32,
xxl: 48,
},
breakpoints: {
mobile: 0,
tablet: 768,
desktop: 1024,
}
},
}
Detailed Properties
colors
and alternateColors
colors
: Main color palette (default mode)alternateColors
: Alternative palettes organized by theme (dark, highContrast, etc.)
baseSpacing
Base value used by the spacing system. All padding, margin, gap values, etc. are calculated by multiplying this base value.
radius
Standardized border radius values to maintain visual consistency.
stroke
Standardized border thickness values.
size
Default component heights (buttons, inputs, etc.).
effects
Shadow definitions and other visual effects that can be reused.
typography
fonts
: Available font mapping organized by family, style, and weightdefaults
: Default typographic settings applied when not specified
icons
Icon set available in the application.
presets
Utility functions that return common styles. Useful for frequently repeated patterns.
values
Custom application-specific values that don't fit into other categories.
Theme Result
After creating the theme with createTheme
, you'll have access to your original configurations and additional functionalities that facilitate the use of the styles system:
Original Properties
All configurations you defined remain available:
theme.colors // Active colors (changes according to scheme)
theme.baseColors // Base colors (never change)
theme.alternateColors // Alternative color schemes
theme.typography // Typography settings
theme.icons // Icon set
theme.radius // Border radius values
theme.stroke // Stroke values
theme.size // Component sizes
theme.effects // Visual effects
theme.values // Custom values
theme.presets // Utility functions + default variants
theme.breakpoints // Breakpoints for responsiveness
Color Scheme Functionalities
currentColorScheme()
Returns the current active color scheme:
const activeScheme = theme.currentColorScheme() // 'default', 'dark', etc.
setColorScheme(colorScheme)
Changes the active color scheme:
theme.setColorScheme('dark') // Switch to dark mode
theme.setColorScheme('default') // Return to default scheme
injectColorScheme(name, colorMap)
Dynamically injects a new color scheme:
theme.injectColorScheme('neon', {
background: '#0F0F23',
primary: '#00FF88',
text: '#FFFFFF',
})
theme.setColorScheme('neon') // Can now use the injected scheme
ejectColorScheme(name)
Removes an injected color scheme:
theme.ejectColorScheme('neon') // Removes the custom scheme
Spacing System
baseSpacing
Base value used for spacing calculations:
theme.baseSpacing // 8 (example)
value(multiplier)
Calculates values based on baseSpacing
:
theme.value() // 8 (1 × baseSpacing)
theme.value(2) // 16 (2 × baseSpacing)
theme.value(0.5) // 4 (0.5 × baseSpacing)
spacing
Spacing utilities with different properties:
// Basic function
theme.spacing.value(2) // 16
// Gap
theme.spacing.gap(1) // { gap: 8 }
// Padding (full format)
theme.spacing.padding(2) // { padding: 16 }
theme.spacing.paddingTop(1) // { paddingTop: 8 }
theme.spacing.paddingHorizontal(2) // { paddingLeft: 16, paddingRight: 16 }
theme.spacing.paddingVertical(1) // { paddingTop: 8, paddingBottom: 8 }
// Padding (abbreviated format)
theme.spacing.p(2) // { padding: 16 }
theme.spacing.pt(1) // { paddingTop: 8 }
theme.spacing.px(2) // { paddingLeft: 16, paddingRight: 16 }
theme.spacing.py(1) // { paddingTop: 8, paddingBottom: 8 }
// Margin (full format)
theme.spacing.margin(2) // { margin: 16 }
theme.spacing.marginTop(1) // { marginTop: 8 }
theme.spacing.marginHorizontal(2) // { marginLeft: 16, marginRight: 16 }
theme.spacing.marginVertical(1) // { marginTop: 8, marginBottom: 8 }
// Margin (abbreviated format)
theme.spacing.m(2) // { margin: 16 }
theme.spacing.mt(1) // { marginTop: 8 }
theme.spacing.mx(2) // { marginLeft: 16, marginRight: 16 }
theme.spacing.my(1) // { marginTop: 8, marginBottom: 8 }
Positioning System
inset
Utilities for absolute/fixed positioning:
theme.inset.top(2) // { top: 16 }
theme.inset.bottom(1) // { bottom: 8 }
theme.inset.left(3) // { left: 24 }
theme.inset.right(2) // { right: 16 }
Sizing Utilities
sized(size)
Creates objects with equal width and height:
// With number (multiplies by baseSpacing)
theme.sized(3) // { width: 24, height: 24 }
// With direct value
theme.sized(100) // { width: 800, height: 800 } (if baseSpacing = 8)
theme.sized('50px') // { width: '50px', height: '50px' }
Responsiveness
media
Advanced media query system based on configured breakpoints. Offers different types of queries for greater flexibility:
// Breakpoint configuration in theme
const breakpoints = {
mobile: 0,
tablet: 768,
desktop: 1024,
wide: 1440,
}
Media Query Types
up(breakpoint)
- From breakpoint onwards (inclusive):
theme.media.up('tablet')
// '@media screen and (min-width:768px)'
// Apply styles on tablet and larger screens
const styles = {
container: {
[theme.media.up('tablet')]: {
padding: 24,
}
}
}
down(breakpoint)
- Up to breakpoint (exclusive):
theme.media.down('desktop')
// '@media screen and (max-width:1024px)'
// Apply styles only on screens smaller than desktop
const styles = {
sidebar: {
[theme.media.down('desktop')]: {
display: 'none',
}
}
}
is(breakpoint)
- Exactly at breakpoint:
theme.media.is('tablet')
// '@media screen and (min-width:768px) and (max-width:768px)'
// Apply styles only at exact resolution
const styles = {
element: {
[theme.media.is('tablet')]: {
fontSize: 18,
}
}
}
not(breakpoint)
- Not at breakpoint:
theme.media.not('mobile')
// '@media not screen and (min-width:0px) and (max-width:0px)'
// Apply styles when NOT at specific breakpoint
const styles = {
element: {
[theme.media.not('mobile')]: {
marginTop: 20,
}
}
}
Direct Breakpoint Access
You can also directly access breakpoints as properties (equivalent to up
):
theme.media.tablet // Same as theme.media.up('tablet')
theme.media.desktop // Same as theme.media.up('desktop')
renderToPlatformQuery(props)
Special function to invert queries (useful for platforms that interpret media queries differently):
// Converts queries to opposite behavior
theme.media.renderToPlatformQuery({ up: 'tablet' }) // Returns down query
theme.media.renderToPlatformQuery({ down: 'desktop' }) // Returns up query
theme.media.renderToPlatformQuery({ is: 'mobile' }) // Returns not query
theme.media.renderToPlatformQuery({ not: 'tablet' }) // Returns is query
Complete Practical Example
const styles = {
container: {
padding: 8,
// Mobile landscape and above
[theme.media.up('tablet')]: {
padding: 16,
display: 'flex',
},
// Desktop and above
[theme.media.up('desktop')]: {
padding: 24,
maxWidth: 1200,
},
// Mobile only
[theme.media.down('tablet')]: {
flexDirection: 'column',
},
// Very large screens
[theme.media.up('wide')]: {
margin: '0 auto',
}
},
sidebar: {
display: 'none',
// Show sidebar only on desktop+
[theme.media.up('desktop')]: {
display: 'block',
width: 280,
}
}
}
Border Utilities
border
Border style creator:
theme.border({
width: 1,
color: theme.colors.primary,
style: 'solid'
}) // { borderWidth: 1, borderColor: '#007AFF', borderStyle: 'solid' }
Practical Example
// theme.config.ts
export const lightColors = {
background: '#FFFFFF',
surface: '#F8F9FA',
primary: '#007AFF',
text: '#1C1C1E',
}
export const darkColors = {
background: '#000000',
surface: '#1C1C1E',
primary: '#0A84FF',
text: '#FFFFFF',
}
export const themeConfig = {
colors: lightColors,
alternateColors: {
dark: darkColors,
},
baseSpacing: 8,
// ... rest of configuration
}
// App root
import { createTheme, validateTheme } from '@codeleap/styles'
import { themeConfig } from './theme.config'
const theme = createTheme(
validateTheme(themeConfig),
{
set: (key, value) => AsyncStorage.setItem(key, JSON.stringify(value)),
get: (key) => AsyncStorage.getItem(key).then(JSON.parse),
}
)
export { theme }