Skip to main content

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 by useStylesFor
  • 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>
}