Variants, createStyles and Style Prop
This documentation covers three essential styling concepts: component variants, the createStyles function, and how to use the style prop effectively in your components.
Component Variants
Variants are predefined style configurations that can be applied to components. They provide a consistent way to apply different visual styles without writing custom CSS each time.
This is the preferred first step for real project code. Before writing a stylesheet, check whether built-in or app variants already express what you need.
There are two important sources of variants:
- built-in package variants such as
row,center,p:2,bg:token - app-specific variants registered with
createAppVariants(...)
Dynamic Variants Depend On The Theme
Dynamic variants are not free-form values. They depend on the real app theme.
That means:
color:*,backgroundColor:*,bg:*, andborder*Color:*must map to entries that exist intheme.colorsbr:*,borderRadius:*, corner radius variants, and the currentborder*Width:*/border*Radius:*family must map to entries that exist intheme.radiuseffect:*must map to entries that exist intheme.effects- spacing variants such as
p:*,px:*,mt:*, andgap:*are based on the themebaseSpacing cursor:*andscale:*are dynamic variants too, but they do not depend on theme tokens in the same way
Before using a dynamic variant, inspect the app theme and confirm that the token really exists.
Examples:
bg:neutralSolid200only makes sense ifneutralSolid200exists in the theme color objectcolor:primarySolid500only makes sense ifprimarySolid500exists in the theme color objectbr:largeonly makes sense iflargeexists in the theme radius objecteffect:shadowMdonly makes sense ifshadowMdexists in the theme effects object
Do not invent dynamic variant tokens from memory. The theme is the source of truth.
Available Default Variants
All library components have access to a set of default variants that cover the most common use cases for layout, positioning, and alignment.
Display and Layout
// Display
<View style={['block']} /> // display: block
<View style={['flex']} /> // display: flex, flex: 1
<View style={['hidden']} /> // display: none
// Flex direction
<View style={['row']} /> // display: flex, flexDirection: row
<View style={['column']} /> // flexDirection: column
<View style={['centerRow']} /> // display: flex, flexDirection: row, alignItems: center
Positioning
// Position
<View style={['absolute']} /> // position: absolute
<View style={['relative']} /> // position: relative
<View style={['fixed']} /> // position: fixed
<View style={['sticky']} /> // position: sticky
// Positioning presets
<View style={['insetX']} /> // left: 0, right: 0
<View style={['insetY']} /> // top: 0, bottom: 0
<View style={['whole']} /> // top: 0, bottom: 0, left: 0, right: 0
Sizing
// Dimensions
<View style={['full']} /> // width: 100%, height: 100%
<View style={['fullWidth']} /> // width: 100%
<View style={['fullHeight']} /> // height: 100%
Flexbox Alignment
Align Items (cross axis)
<View style={['alignStart']} /> // alignItems: flex-start
<View style={['alignEnd']} /> // alignItems: flex-end
<View style={['alignCenter']} /> // alignItems: center
<View style={['alignStretch']} /> // alignItems: stretch
Justify Content (main axis)
<View style={['justifyStart']} /> // justifyContent: flex-start
<View style={['justifyEnd']} /> // justifyContent: flex-end
<View style={['justifyCenter']} /> // justifyContent: center
<View style={['justifySpaceBetween']} /> // justifyContent: space-between
<View style={['justifySpaceAround']} /> // justifyContent: space-around
Align Self (self-alignment)
<View style={['alignSelfCenter']} /> // alignSelf: center
<View style={['alignSelfStart']} /> // alignSelf: flex-start
<View style={['alignSelfEnd']} /> // alignSelf: flex-end
<View style={['alignSelfStretch']} /> // alignSelf: stretch
Centering Preset
<View style={['center']} /> // alignItems: center, justifyContent: center
Advanced Flexbox
// Flex wrap
<View style={['wrap']} /> // flexWrap: wrap
// Text
<Text style={['noWrap']} /> // whiteSpace: nowrap
Text Alignment
<Text style={['textLeft']} /> // textAlign: left
<Text style={['textCenter']} /> // textAlign: center
<Text style={['textRight']} /> // textAlign: right
Spacing Variants
Spacing variants require you to place the value after the : and remember that the final result will be a multiplication of the baseSpacing value defined in theme creation.
<View style={['padding:1']} /> // padding: baseSpacing * 1
<View style={['paddingBottom:2']} /> // paddingBottom: baseSpacing * 2
<View style={['margin:2']} /> // margin: baseSpacing * 2
<View style={['marginTop:2']} /> // marginTop: baseSpacing * 2
<View style={['gap:1']} /> // gap: baseSpacing * 1
Short Variants
Spacing variants can be used with their full name, but for brevity, you can use their short version:
<View style={['p:1']} /> // Padding
<View style={['pt:1']} /> // Padding top
<View style={['pb:1']} /> // Padding bottom
<View style={['pl:1']} /> // Padding left
<View style={['pr:1']} /> // Padding right
<View style={['px:1']} /> // Padding horizontal
<View style={['py:1']} /> // Padding vertical
<View style={['m:1']} /> // Margin
<View style={['mt:1']} /> // Margin top
<View style={['mb:1']} /> // Margin bottom
<View style={['ml:1']} /> // Margin left
<View style={['mr:1']} /> // Margin right
<View style={['mx:1']} /> // Margin horizontal
<View style={['my:1']} /> // Margin vertical
These short variants are especially important in real project code. For normal screens and components, they are usually the fastest and most correct path before reaching for createStyles(...).
Practical Example with Short Variants
// Layout using short variants for spacing
<View style={['row', 'p:2', 'gap:1', 'bg:neutralSolid100']}>
<Text style={['color:primarySolid500']}>Title</Text>
<Button style={['primary']} />
</View>
Color Variants
Color variants require you to place which color after the :
// Text color variants
<Text style={['color:neutralSolid600']} />
<Text style={['color:neutralSolid500']} />
<Text style={['color:primarySolid500']} />
// Background variants
<View style={['bg:neutralSolid600']} />
<View style={['bg:neutralSolid500']} />
<View style={['bg:primarySolid500']} />
Those color tokens come from theme.colors, so always check the project theme before choosing them.
Radius Variants
Radius variants depend on the radius entries defined in the theme:
<View style={['br:small']} />
<View style={['br:medium']} />
<View style={['br:large']} />
Those values only work when the corresponding keys exist in theme.radius.
The dynamic system also supports the longer radius families:
<View style={['borderRadius:large']} />
<View style={['borderTopLeftRadius:xl']} />
<View style={['borderBottomRightRadius:2xl']} />
Border Color, Width, and Radius Families
The dynamic variant system also supports border families:
<View style={['borderColor:primarySolid500']} />
<View style={['borderTopColor:dangerSolid500']} />
<View style={['borderLeftWidth:md']} />
<View style={['borderTopRadius:lg']} />
Important implementation detail:
border*Color:*usestheme.colorsborder*Width:*currently resolves throughtheme.radiusborder*Radius:*also resolves throughtheme.radius
So the AI should follow the real implementation, not assume generic CSS naming rules.
Effect Variants
Effect variants depend on theme.effects:
<View style={['effect:shadowMd']} />
Non-theme Dynamic Variants
Some dynamic variants are not driven by theme token maps:
<View style={['cursor:pointer']} />
<View style={['scale:1.25']} />
cursor:*uses the supported cursor values from the packagescale:*accepts numeric values and is rendered differently for browser and native environments
Practical Combination Examples
Breakpoints Also Depend On The Theme
Responsive syntax is not free-form either. Breakpoint names such as mobile, tablet, desktop, or wide only work when those names actually exist in the configured app theme.
That means:
- breakpoint-prefixed strings such as
tablet:px:3depend on a realtabletbreakpoint in the theme breakpointsobject keys such astablet:upordesktop:downalso depend on real theme breakpoint names- do not invent breakpoint names from memory
Always inspect the theme breakpoints before writing responsive style prop logic.
Header Layout
<View style={['row', 'alignCenter', 'justifySpaceBetween', 'fullWidth', 'p:2']}>
<Text style={['h2']}>Title</Text>
<Button style={['primary']} text="Action" />
</View>
Centered Card
<View style={['center', 'fullHeight', 'p:3']}>
<View style={['relative', 'centerRow', 'gap:2', 'bg:surface', 'p:4']}>
<Icon name="check" />
<Text style={['h3', 'color:success']}>Success!</Text>
</View>
</View>
Horizontal List with Scroll
<View style={['row', 'alignCenter', 'gap:2', 'wrap', 'p:2']}>
{items.map(item => (
<Button
key={item.id}
style={['secondary', 'px:3', 'py:1']}
text={item.name}
/>
))}
</View>
Custom Component Variants
When creating a stylesheet file for a component, you can create your own variants for it, and these variants you create will be available to use through the style prop.
const createComponentVariant = createStyles<ComponentComposition>
export const ComponentStyles = {
default: createComponentVariant((theme) => ({
wrapper: {
...theme.presets.center,
...theme.presets.fullWidth,
},
})),
primary: createComponentVariant((theme) => ({
wrapper: {
backgroundColor: theme.colors.primary,
borderRadius: theme.radius.medium,
...theme.spacing.padding(2),
},
})),
outlined: createComponentVariant((theme) => ({
wrapper: {
borderWidth: 1,
borderColor: theme.colors.primary,
backgroundColor: 'transparent',
},
})),
}
You can use it in the component:
<Component style={['primary']} />
<Component style={['outlined', 'p:3']} />
App-wide custom variants
When the project wants reusable custom style strings across many components, register them in the app styles module with createAppVariants(...):
import { createAppVariants } from '@codeleap/styles'
export const appVariants = createAppVariants({
elevatedCard: (theme) => ({
backgroundColor: theme.colors.neutralSolid0,
borderRadius: theme.radius.large,
...theme.effects.elevated,
}),
})
That makes elevatedCard available through the normal style prop language.
The createStyles Function
createStyles is used to create custom styles that have access to the theme. It's particularly useful for styles that cannot be achieved through variants alone.
The preferred project form is:
const styles = createStyles((theme) => ({
// themed stylesheet
}))
Prefer this after variants are no longer enough.
Conditional Style Prop Values
The style prop accepts more than just strings and objects. The type system also allows conditional values such as:
booleannull''- arrays mixing those values with variants and style objects
This is useful for normal conditional UI styling:
<View
style={[
'row',
isActive && 'bg:primarySolid500',
disabled && { opacity: 0.5 },
hasError ? 'borderColor:dangerSolid500' : null,
]}
/>
This means the AI should prefer the normal conditional style-array pattern instead of building a separate temporary styles object just to toggle one or two variants.
Basic Usage
import { createStyles } from '@codeleap/styles'
// Static object support exists, but in real project code the themed function form is usually the better default
const styles = createStyles({
imageWrapper: {
flex: 1,
height: 200,
borderRadius: 12,
},
image: {
width: '70%',
aspectRatio: 1,
},
})
Accessing Theme Properties
The createStyles function receives the application theme and with that you have access to all the functionalities we've already described in the theme section.
const styles = createStyles((theme) => ({
container: {
// Colors
backgroundColor: theme.colors.surface,
borderColor: theme.colors.primary,
// Spacing
...theme.spacing.padding(2),
...theme.spacing.marginVertical(1),
// Border radius
borderRadius: theme.radius.medium,
// Presets
...theme.presets.center,
...theme.presets.shadow,
// Custom values
height: theme.values.buttonHeight,
width: theme.values.width / 2,
},
header: {
...theme.presets.row,
...theme.spacing.paddingHorizontal(3),
backgroundColor: theme.colors.primarySolid100,
},
content: {
flex: 1,
...theme.spacing.padding(2),
},
}))
The Style Prop
The style prop is the heart of the system, accepting a flexible array of styles that can include variants, custom objects, nested styles, and responsive breakpoints.
Basic Style Prop Syntax
// Single variant as string
<View style='flex' />
// Multiple variants and utilities
<View style={['flex', 'gap:2', 'padding:1']} />
// Combining variants with custom styles
<View style={['flex', 'center', styles.customContainer]} />
Inline Style Objects
// Custom CSS directly in the prop
<View style={[
'flex',
'center',
{
backgroundColor: 'red',
borderRadius: 8,
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
}
]} />
Nested Styles
You can style directly the composition components of the main component
When using nested composition styles, follow the exact composition keys exported by the component. For package components, inspect the installed source in node_modules. For project components, inspect the project stylesheet file. Do not invent slot names or state keys from memory. Keys such as icon, touchableWrapper, or icon:disabled are only valid when that specific component composition actually exposes them.
// Styling child elements through the parent component
<View style={[
'flex',
'center',
{
backgroundColor: 'red',
// Styles for child elements
innerWrapper: ['flex', 'center', { opacity: 0.5 }],
title: ['h1', { color: 'white', textAlign: 'center' }],
button: ['primary', { marginTop: 16 }],
// Pseudo-states
hover: { opacity: 0.8 },
active: { transform: 'scale(0.98)' },
}
]} />
Responsive Breakpoints (web only)
You can open a breakpoints object and the key will be one of the breakpoints defined in theme creation
// Different styles for different screen sizes
<View style={[
'flex',
'center',
{ backgroundColor: 'red' },
{
breakpoints: {
mobile: [
'column',
'p:2',
{ gap: 8 }
],
tablet: [
'alignStart',
'p:3',
{
backgroundColor: 'blue',
maxWidth: 768
}
],
desktop: [
'row',
'p:4',
{
padding: 20,
maxWidth: 1200,
margin: '0 auto'
}
]
}
}
]} />
Best Practices
When to Use Each Approach
Variants: For quick and direct styles
// Default variants for layout
<View style={['row', 'alignCenter', 'gap:2']} />
<Text style={['h1', 'textCenter', 'color:primary']} />
// Custom variants for specific components
<Button style={['primary']} />
<Card style={['elevated', 'rounded']} />
createStyles: For complex and custom styles that need theme access
const styles = createStyles((theme) => ({
complexLayout: {
height: theme.values.height / 3,
...theme.presets.center,
background: `linear-gradient(45deg, ${theme.colors.primary}, ${theme.colors.secondary})`,
},
}))
Inline Objects: For specific and unique adjustments
<View style={['flex', { backgroundColor: 'rgba(0,0,0,0.05)' }]} />
Combining All Approaches
// ✅ Complete example using all functionalities
<View style={[
// 1. Base variants for structure
'flex',
'column',
// 2. Short variants for quick spacing
'gap:2',
'p:2',
// 3. Custom styles from createStyles
styles.containerBase,
// 4. Inline objects for specific adjustments
{
backgroundColor: 'rgba(0,0,0,0.05)',
borderRadius: 12,
// 5. Nested styles for child elements
header: [
'row',
'alignCenter',
'justifySpaceBetween',
'pb:2',
{ borderBottomWidth: 1, borderBottomColor: '#eee' }
],
content: [
'flex',
'gap:1',
styles.contentArea
]
},
// 6. Breakpoints for responsiveness
{
breakpoints: {
mobile: [
'p:1',
{
header: ['column', 'alignStart', 'gap:1'],
content: ['gap:0.5']
}
],
desktop: [
'p:3',
{
maxWidth: 800,
margin: '0 auto'
}
]
}
}
]} />
// ✅ For simple components, keep it simple
<View style={['row', 'alignCenter', 'gap:2', 'p:2']} />
<Text style={['h1', 'textCenter', 'color:primary']} />
<Button style={['primary']} />
Final Tips
- Prioritize variants for consistency, simplicity, and performance
- Use createStyles when you need theme access
- Combine approaches when necessary, but maintain readability
- Prefer short variants (p:2 vs padding:2) for cleaner code
Anti-patterns
These are the most common mistakes when using @codeleap/styles. AI agents and new developers should read this carefully.
// ❌ Never use StyleSheet.create() — it bypasses the theme system
const styles = StyleSheet.create({
container: { padding: 16, backgroundColor: '#007AFF' }
})
// ✅ Use createStyles() instead
const styles = createStyles((theme) => ({
container: { ...theme.spacing.padding(2), backgroundColor: theme.colors.primary }
}))
// ❌ Never hardcode spacing values — they won't respect baseSpacing
<View style={{ padding: 16, gap: 8 }} />
// ✅ Use spacing variants
<View style={['p:2', 'gap:1']} />
// ❌ Never hardcode color values — they won't update with theme/dark mode
<Text style={{ color: '#007AFF' }} />
// ✅ Use color tokens from the theme
<Text style={['color:primary']} />
// or in createStyles:
<Text style={[styles.text]} /> // where styles.text = { color: theme.colors.primary }
// ❌ Never pass a plain style object as the style prop
<View style={{ flexDirection: 'row', alignItems: 'center' }} />
// ✅ Use string variants
<View style={['row', 'alignCenter']} />
// ❌ Don't skip the 'default' variant in component stylesheets
export const MyStyles = {
primary: createVariant((theme) => ({ ... })) // missing 'default'!
}
// ✅ Always include 'default' — it's mandatory
export const MyStyles = {
default: createVariant((theme) => ({ ... })),
primary: createVariant((theme) => ({ ... })),
}