Creating Project Components with Styling System
This guide explains how to create custom components in projects that use the styling system, highlighting the differences from base library components.
This is one of the most important architectural rules in the package: reusable project UI should follow the component file plus component stylesheet file pattern instead of inlining all styling logic in one place.
Key Differences
When creating components in the project (instead of the library), there are some important differences:
- Use of
ICSSinstead ofStyledProp - Registration in the project's
StyleRegistry - Typing with
StyledComponentfrom the library - Reliance on the project app styles module for
StyleRegistry, theme setup, and app variants
Basic Component Structure
Implementation Pattern
import React from 'react'
import { View } from '@/components'
import { useStylesFor } from '@codeleap/mobile'
import { StyledComponent } from '@codeleap/styles'
import { StyleSheets, StyleRegistry } from '@/app'
export type ComponentProps = {}
export const Component: StyledComponent<typeof StyleSheets.ComponentStyles, ComponentProps> = (props) => {
const {
style,
...rest
} = props
const styles = useStylesFor(Component.styleRegistryName, style)
return (
<View {...rest} style={styles.wrapper} />
)
}
Component.styleRegistryName = 'Component'
Component.elements = ['wrapper']
Component.rootElement = 'wrapper'
StyleRegistry.registerComponent(Component)
Key Creation Differences
1. Typing
- Library:
StyledProp<ComponentComposition> - Project:
ICSS
2. Registry
- Library:
MobileStyleRegistry.registerComponent - Project:
StyleRegistry.registerComponent
3. Typed Component
- Library: Manual
withVariantTypes - Project:
StyledComponent<typeof StyleSheets.ComponentStyles, Props>
This pattern allows creating components fully integrated with the project's styling system, maintaining flexibility and reusability while benefiting from the robust theming system.
rootElement should normally point to the true root styled element of the component. If you do not set it, the registry behavior falls back to 'wrapper', so only omit it when wrapper is really the root element.
The important architectural rule is: project components should plug into the existing app styles setup instead of recreating their own theme or registry logic locally.
The second important rule is: the component file and the component stylesheet file have different responsibilities.
- the component file renders the composition and consumes
style - the stylesheet file defines the registered variants and composition styling
When the component renders another styled child component, the correct pattern is:
- resolve the parent styles with
useStylesFor(...) - derive the child style props with
useCompositionStyles(...) - pass those derived styles to the child component
styleprop
This is the correct composition flow for child styled components. Do not invent an ad hoc extraction pattern.
useNestedStylesByKey(...) exists in the package, but it should not be the default pattern for normal composed child styling. The preferred agent-facing pattern is still useCompositionStyles(...).
For composed components, the stylesheet must also stay aligned with the exact exported composition contract.
- for project components, declare and export the real composition type in the stylesheet file with the variants
- import the real composition type instead of inventing keys
- use exact slot names such as
touchableWrapperoricononly when they belong to that component - use state keys like
slot:disabledonly when the composition supports them
Stylesheet
In the component's stylesheet file, you need to declare the typing of its composition, for example:
import { createStyles } from '@codeleap/styles'
import { StyleRegistry } from '../styles'
export type ComponentComposition = 'wrapper' | 'innerWrapper'
const createComponentVariant = createStyles<ComponentComposition>
export const ComponentStyles = {
default: createComponentVariant(theme => ({
wrapper: {
width: '100%',
},
innerWrapper: {
...theme.presets.flex,
},
})),
}
StyleRegistry.registerVariants('Component', ComponentStyles)
For project components, this stylesheet file is usually the source of truth for the composition contract. The component implementation should follow it instead of inventing extra slots later in JSX or style objects.