Creating Styled Components
The styles system provides a comprehensive way to create reusable, themable components with integrated styling capabilities. This guide will walk you through creating components that integrate seamlessly with the theme system.
Basic Component Structure
Every styled component follows a consistent pattern that includes type definitions, style registration, and the component implementation itself.
Component Implementation Pattern
import React from 'react'
import { useStylesFor } from './useStylesFor'
import { MobileStyleRegistry } from './MobileStyleRegistry'
import { AnyRecord, IJSX, StyledComponentProps } from '@codeleap/styles'
export const Component = (props: ComponentProps) => {
const { style, ...rest } = props
const styles = useStylesFor(Component.styleRegistryName, style)
return (
<Component {...rest} style={styles.wrapper} />
)
}
// Component metadata
Component.styleRegistryName = 'ComponentName'
Component.elements = ['wrapper']
Component.rootElement = 'wrapper'
Component.withVariantTypes = <S extends AnyRecord>(styles: S) => {
return Component as (props: StyledComponentProps<ComponentProps, typeof styles>) => IJSX
}
// Register component in the styles system
MobileStyleRegistry.registerComponent(Component)
Composition Components
For components that are composed of other styled components, use the useCompositionStyles
hook to pass styles to child components.
useCompositionStyles
Hook
import { useCompositionStyles } from './useCompositionStyles'
export const Component = (props: ComponentProps) => {
const { style, ...rest } = props
const styles = useStylesFor(Component.styleRegistryName, style)
const compositionStyles = useCompositionStyles(['loader'], styles)
return (
<View style={styles.wrapper}>
<ActivityIndicator style={compositionStyles.loader} />
</View>
)
}
Component.styleRegistryName = 'Component'
Component.elements = ['wrapper', 'text', 'loader']
Component.rootElement = 'wrapper'
Component.withVariantTypes = <S extends AnyRecord>(styles: S) => {
return Component as (props: StyledComponentProps<ComponentProps, typeof styles>) => IJSX
}
MobileStyleRegistry.registerComponent(Component)
How it works
useCompositionStyles
allows you to pass specific styles to child components that are also part of the styles system:
- First parameter: Array with the names of elements that will be passed to child components
- Second parameter: The
styles
object returned byuseStylesFor
- Returns: Object with styles formatted to be passed as the
style
prop of child components
// styles.wrapper -> applied directly to the element
// styles.loader -> transformed into compositionStyles.loader for the child component
const compositionStyles = useCompositionStyles(['loader', 'text'], styles)
Component Anatomy
1. Style Integration
useStylesFor
Hook
This hook retrieves and processes styles for your component:
const styles = useStylesFor(Component.styleRegistryName, style)
- First parameter: Component's registry name (string identifier)
- Second parameter: Style overrides passed through props
- Returns: Processed styles object with all component elements
2. Component Metadata
Every styled component requires specific metadata properties:
styleRegistryName
Unique identifier for the component in the styles registry:
MyComponent.styleRegistryName = 'MyComponent'
elements
Array of all styleable elements in the component:
MyComponent.elements = ['wrapper', 'content', 'icon']
rootElement
The main/root element of the component:
MyComponent.rootElement = 'wrapper'
withVariantTypes
Method to provide TypeScript support for custom variants:
MyComponent.withVariantTypes = <S extends AnyRecord>(styles: S) => {
return MyComponent as (props: StyledComponentProps<MyComponentProps, typeof styles>) => IJSX
}
3. Registry Registration
Register the component to make it available in the styles system:
MobileStyleRegistry.registerComponent(MyComponent)
Best Practices
1. Consistent Naming
- Use PascalCase for component names
- Use camelCase for element names
- Make styleRegistryName match the component name
File Structure
Organize your component files consistently:
MyComponent/
├── index.ts # Component implementation
├── types.ts # TypeScript interfaces
└── styles.ts # Style definitions
styles.ts
For simple components:
export type ComponentComposition = 'wrapper'
For composition components:
import { ActivityIndicatorComposition } from '../ActivityIndicator'
export type ComponentComposition = 'wrapper' | `loader${Capitalize<ActivityIndicatorComposition>}`
types.ts
import { StyledProp } from '@codeleap/styles'
import { ComponentComposition } from './styles'
export type ComponentProps = {
style?: StyledProp<ComponentComposition>
}