Skip to main content

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 of createTheme used to persist important theme information:
    • set(name, value): Function to save data
    • get(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 weight
  • defaults: 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 }