Streamplace ZeroCSS
Streamplace ZeroCSS (zero-compile css) is a comprehensive styling system built on design tokens and atomic utilities, providing a consistent and maintainable approach to styling React Native components across all platforms.
What is ZeroCSS?
Section titled “What is ZeroCSS?”ZeroCSS is Streamplace’s zero-configuration, zero-configuration atomic styling system designed specifically for React Native development. The name reflects its core philosophy: zero setup, zero boilerplate, and zero friction styling.
Overview
Section titled “Overview”Streamplace ZeroCSS is inspired by Tailwind CSS, and ALF on bluesky-social/social-app, featuring:
- Atomic utilities: Small, composable style objects
- Design tokens: Consistent spacing, colors, and typography
- Platform awareness: iOS, Android, and web-specific styles
- Type safety: Full TypeScript support
- Performance: Optimized for React Native’s style system
Core Concepts
Section titled “Core Concepts”Atoms are the building blocks of ZeroCSS. They provide direct access to design tokens in a composable format:
import { atoms } from "@streamplace/components";
const { layout, colors, spacing, borders } = atoms;
// Usage<View style={[ layout.flex.row, layout.flex.center, { backgroundColor: colors.gray[100] }, ]}/>;
Pairify Function
Section titled “Pairify Function”The pairify
function converts design tokens into style objects that can be
used directly:
// Instead of writing:{ marginTop: 16;}
// You can write:mt[4]; // where 4 = 16px in the spacing scale
You can also directly make your own custom styles with pairify
:
let bw = pairify( { thin: 1, medium: 2, thick: 4, }, "borderWidth",)
// bw.thin will be { borderWidth: 1 }, etc.<View style={[bw.thin]} />
Design Tokens
Section titled “Design Tokens”Colors
Section titled “Colors”Streamplace uses a tailwind-like with semantic scales:
// Primary colorscolors.primary[500]; // #3b82f6colors.primary[600]; // #2563eb
// Grayscalecolors.gray[50]; // #fafafacolors.gray[900]; // #171717
// Semantic colorscolors.destructive[500]; // #ef4444colors.success[500]; // #22c55ecolors.warning[500]; // #f59e0b
// Platform-specific colorscolors.ios.systemBlue; // #007AFFcolors.android.materialBlue; // #2196F3
Spacing
Section titled “Spacing”Consistent spacing scale following the 8px grid system: (em/rem is not available in React Native)
spacing[0]; // 0pxspacing[1]; // 4pxspacing[2]; // 8pxspacing[3]; // 12pxspacing[4]; // 16pxspacing[5]; // 20pxspacing[6]; // 24pxspacing[8]; // 32pxspacing[10]; // 40pxspacing[12]; // 48pxspacing[16]; // 64pxspacing[20]; // 80px// ... up to spacing[96] = 384px
Typography
Section titled “Typography”Platform-aware typography system:
// Universal typography (works on all platforms)typography.universal.body.fontSize; // 16typography.universal.body.lineHeight; // 24
// Platform-specifictypography.ios.body.fontFamily; // "SF Pro Text"typography.android.body.fontFamily; // "Roboto"
Atomic Utilities
Section titled “Atomic Utilities”Layout
Section titled “Layout”import { layout } from "@streamplace/components";
// Flexboxlayout.flex.row; // { flexDirection: "row" }layout.flex.column; // { flexDirection: "column" }layout.flex.center; // { justifyContent: "center", alignItems: "center" }layout.flex.spaceBetween; // { justifyContent: "space-between" }
// Positioninglayout.position.absolute; // { position: "absolute" }layout.position.relative; // { position: "relative" }
Spacing
Section titled “Spacing”import { m, mt, mr, mb, ml, mx, my, p, pt, pr, pb, pl, px, py,} from "@streamplace/components";
// Marginm[4]; // { margin: 16 }mt[2]; // { marginTop: 8 }mx[3]; // { marginHorizontal: 12 }my[4]; // { marginVertical: 16 }
// Paddingp[4]; // { padding: 16 }pt[2]; // { paddingTop: 8 }px[3]; // { paddingHorizontal: 12 }py[4]; // { paddingVertical: 16 }
Sizing
Section titled “Sizing”import { w, h, sizes } from "@streamplace/components";
// Width and heightw[10]; // { width: 40 }h[20]; // { height: 80 }w.percent[50]; // { width: "50%" }h.percent[100]; // { height: "100%" }
// Min/max sizessizes.minWidth[20]; // { minWidth: 80 }sizes.maxHeight[64]; // { maxHeight: 256 }
Colors
Section titled “Colors”import { bg, text, borders } from "@streamplace/components";
// Background colorsbg.gray[100]; // { backgroundColor: "#f5f5f5" }bg.primary[500]; // { backgroundColor: "#3b82f6" }
// Text colorstext.gray[900]; // { color: "#171717" }text.primary[600]; // { color: "#2563eb" }
// Border colorsborders.color.gray[300]; // { borderColor: "#d4d4d4" }
Borders
Section titled “Borders”import { borders } from "@streamplace/components";
// Border widthsborders.width.thin; // { borderWidth: 1 }borders.width.medium; // { borderWidth: 2 }borders.width.thick; // { borderWidth: 4 }
// Border stylesborders.style.solid; // { borderStyle: "solid" }borders.style.dashed; // { borderStyle: "dashed" }
// Directional bordersborders.top.width.thin; // { borderTopWidth: 1 }borders.top.color.gray[300]; // { borderTopColor: "#d4d4d4" }
Advanced Usage
Section titled “Advanced Usage”Responsive Styling
Section titled “Responsive Styling”Use the responsiveValue
utility for responsive designs:
import { responsiveValue } from "@streamplace/components";import { useWindowDimensions } from "react-native";
function MyComponent() { const { width } = useWindowDimensions();
const padding = responsiveValue( { sm: 8, md: 16, lg: 24, xl: 32, default: 8, }, width, );
return <View style={{ padding }} />;}
Platform-Specific Styles
Section titled “Platform-Specific Styles”import { platformStyle } from "@streamplace/components";
const styles = platformStyle({ ios: { shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, }, android: { elevation: 4, }, web: { boxShadow: "0 2px 4px rgba(0,0,0,0.1)", }, default: { borderWidth: 1, borderColor: "#e5e5e5", },});
Style Merging
Section titled “Style Merging”import { mergeStyles } from "@streamplace/components";
const baseStyles = { padding: 16, backgroundColor: "#fff" };const variantStyles = { borderRadius: 8 };const conditionalStyles = isActive ? { backgroundColor: "#f0f0f0" } : {};
const finalStyles = mergeStyles(baseStyles, variantStyles, conditionalStyles);
Animations
Section titled “Animations”For animations, use react-native-reanimated
with ZeroCSS:
import Animated, { useAnimatedStyle, useSharedValue,} from "react-native-reanimated";import { bg, p, r } from "@streamplace/components";
function AnimatedComponent() { const opacity = useSharedValue(1);
const animatedStyle = useAnimatedStyle(() => ({ opacity: opacity.value, }));
return ( <Animated.View style={[bg.white, p[4], r[2], animatedStyle]}> {/* content */} </Animated.View> );}
Best Practices
Section titled “Best Practices”1. Use Atomic Utilities First
Section titled “1. Use Atomic Utilities First”// Good<View style={[layout.flex.row, bg.gray[100], p[4]]} />
// Avoid<View style={{ flexDirection: "row", backgroundColor: "#f5f5f5", padding: 16}} />
2. Combine Atoms with Custom Styles
Section titled “2. Combine Atoms with Custom Styles”// Good<View style={[ layout.flex.center, bg.primary[500], { borderRadius: 8 }, // Custom style when needed ]}/>
3. Use Style Arrays for Composition
Section titled “3. Use Style Arrays for Composition”const baseStyles = [layout.flex.column, bg.white, p[4]];const variantStyles = isActive ? [bg.primary[50], borders.color.primary[200]] : [];
<View style={[...baseStyles, ...variantStyles]} />;
4. Leverage TypeScript
Section titled “4. Leverage TypeScript”// All atoms are fully typedimport { atoms } from "@streamplace/components";
// TypeScript will provide autocomplete and catch errorsconst { layout, colors } = atoms;
5. Follow the Design System
Section titled “5. Follow the Design System”// Use the spacing scalep[4]; // 16px - follows 8px gridmt[2]; // 8px
// Use semantic colorsbg.primary[500]; // Brand primarytext.destructive[600]; // Error text
Migration Guide
Section titled “Migration Guide”From Inline Styles
Section titled “From Inline Styles”// Before<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center", padding: 16, backgroundColor: "#fff"}} />
// After<View style={[ layout.flex.row, layout.flex.spaceBetween, layout.flex.alignCenter, p[4], bg.white]} />
From StyleSheet
Section titled “From StyleSheet”// Beforeconst styles = StyleSheet.create({ container: { flex: 1, padding: 16, backgroundColor: "#f5f5f5", },});
// Afterconst containerStyles = [flex.values[1], p[4], bg.gray[100]];
Testing
Section titled “Testing”When testing components with ZeroCSS:
import { render } from "@testing-library/react-native";import { atoms } from "@streamplace/components";
const { layout } = atoms;
test("applies correct styles", () => { const { getByTestId } = render( <View testID="test-view" style={[layout.flex.center, { backgroundColor: "#fff" }]} />, );
const view = getByTestId("test-view"); expect(view).toHaveStyle({ justifyContent: "center", alignItems: "center", backgroundColor: "#fff", });});
Performance Considerations
Section titled “Performance Considerations”- Style Objects Are Cached: Atomic utilities create cached style objects for optimal performance
- Avoid Dynamic Styles: Use conditional arrays instead of dynamic style objects
- Use StyleSheet.create(): For complex custom styles, still use StyleSheet.create()
// Good - styles are cachedconst styles = [layout.flex.row, bg.white, p[4]];
// Less optimal - creates new object each renderconst styles = { flexDirection: "row", backgroundColor: colors.white, padding: spacing[4],};
Responsive Mobile Player Example
Section titled “Responsive Mobile Player Example”The responsive mobile player demonstrates advanced usage of ZeroCSS with responsive layouts, animations, and platform-aware styling:
// useResponsiveLayout.ts - Custom hook for responsive logicimport { useWindowDimensions } from "react-native";import { useSafeAreaInsets } from "react-native-safe-area-context";import { responsiveValue } from "@streamplace/components/src/lib/utils";
export function useResponsiveLayout() { const { width: screenWidth, height: screenHeight } = useWindowDimensions(); const safeAreaInsets = useSafeAreaInsets();
const isLandscape = screenWidth > screenHeight; const isMediumScreen = screenWidth >= 768; const shouldShowChatSidePanel = isLandscape && isMediumScreen;
const chatPanelWidth = responsiveValue( { md: 320, lg: 400, xl: 480, default: 300, }, screenWidth, );
return { shouldShowChatSidePanel, chatPanelWidth, safeAreaInsets, // ... other responsive values };}
// Mobile UI Component with responsive stylingimport { atoms, px, py, r } from "@streamplace/components";import Animated, { useAnimatedStyle, withSpring,} from "react-native-reanimated";
const { layout, borders, position, gap } = atoms;
export function MobileUi() { const { shouldShowChatSidePanel, chatPanelWidth, safeAreaInsets } = useResponsiveLayout();
return ( <> {/* Floating controls with safe area support */} <View style={[ layout.position.absolute, { padding: 6.5, backgroundColor: "rgba(0, 0, 0, 0.6)", top: safeAreaInsets.top + 8, }, r[2], position.left[1], ]} > <View style={[layout.flex.row, layout.flex.center, gap.all[2]]}> {/* Controls */} </View> </View>
{/* Responsive chat panel */} {shouldShowChatSidePanel ? ( <Animated.View style={[ layout.position.absolute, position.right[0], { top: safeAreaInsets.top, bottom: safeAreaInsets.bottom, width: chatPanelWidth, backgroundColor: "rgba(0, 0, 0, 0.85)", borderLeftWidth: 1, borderLeftColor: "rgba(255, 255, 255, 0.1)", }, ]} > <ChatPanel /> </Animated.View> ) : ( <View style={[ layout.position.absolute, position.bottom[0], { width: "100%" }, ]} > <Resizable> <ChatPanel /> </Resizable> </View> )}
{/* Desktop metadata bar */} {isDesktop && ( <View style={[ layout.position.absolute, { bottom: safeAreaInsets.bottom, left: safeAreaInsets.left, right: shouldShowChatSidePanel ? chatPanelWidth + safeAreaInsets.right : safeAreaInsets.right, height: 80, backgroundColor: "rgba(0, 0, 0, 0.9)", borderTopWidth: 1, borderTopColor: "rgba(255, 255, 255, 0.1)", }, px[5], py[4], ]} > <View style={[layout.flex.row, layout.flex.center, gap.all[6]]}> {/* Metadata content */} </View> </View> )} </> );}
This example demonstrates:
- Responsive design: Different layouts for mobile/tablet/desktop
- Safe area handling: Proper support for notched devices
- Animations: Smooth transitions using
react-native-reanimated
- Atomic styling: Consistent use of design tokens
- Platform awareness: Adaptive layouts based on screen size
🎯 ZeroCSS Export Usage
Section titled “🎯 ZeroCSS Export Usage”The new zero
export provides a clean namespace for all ZeroCSS utilities:
// Import the zero namespaceimport * as zero from "@streamplace/components/zero";
// All ZeroCSS utilities are available under the zero namespace<View style={[ zero.layout.flex.column, zero.bg.white, zero.borders.width.thin, zero.p[4], zero.r[2], ]}/>;
// Responsive utilitiesconst padding = zero.responsiveValue( { sm: 8, md: 16, lg: 24, default: 8, }, screenWidth,);
Customization and Overrides
Section titled “Customization and Overrides”ZeroCSS is designed to be extensible and customizable. Here are the main approaches for overriding or configuring styles:
1. Style Array Composition (Recommended)
Section titled “1. Style Array Composition (Recommended)”The most common way to override ZeroCSS styles is by using style arrays where later styles override earlier ones:
import { atoms, bg, p, r } from "@streamplace/components";
const { layout } = atoms;
// Base ZeroCSS styles with custom overrides<View style={[ layout.flex.column, bg.primary[500], p[4], r[2], // Custom overrides { backgroundColor: "#custom-color", // Overrides bg.primary[500] borderRadius: 12, // Overrides r[2] }, ]}/>;
2. Conditional Style Overrides
Section titled “2. Conditional Style Overrides”Use conditional logic to override styles based on state or props:
import { bg, p, r, borders } from "@streamplace/components";
function CustomButton({ variant = "primary", disabled = false }) { return ( <Pressable style={[ // Base ZeroCSS styles bg.primary[500], p[4], r[2], borders.width.thin,
// Conditional overrides variant === "secondary" && { backgroundColor: colors.gray[500], borderColor: colors.gray[600], },
disabled && { backgroundColor: colors.gray[300], opacity: 0.6, }, ]} > {/* content */} </Pressable> );}
3. Custom Style Variants
Section titled “3. Custom Style Variants”Create your own style variants that extend ZeroCSS:
import { atoms, bg, text, p, r } from "@streamplace/components";
const { layout } = atoms;
// Custom component variantsconst buttonVariants = { primary: [bg.primary[500], text.white], secondary: [bg.gray[500], text.white], outline: [ { backgroundColor: "transparent" }, text.primary[600], { borderWidth: 1, borderColor: colors.primary[500] }, ], ghost: [{ backgroundColor: "transparent" }, text.primary[600]],};
function CustomButton({ variant = "primary", children, ...props }) { return ( <Pressable style={[ // Base ZeroCSS styles layout.flex.center, p[4], r[2], // Apply variant ...buttonVariants[variant], ]} {...props} > <Text>{children}</Text> </Pressable> );}
4. Extending Design Tokens
Section titled “4. Extending Design Tokens”For systematic customization, extend the design tokens:
import { colors, spacing } from "@streamplace/components";
// Custom design tokens that extend ZeroCSSconst customTokens = { colors: { ...colors, brand: { 50: "#f0f9ff", 500: "#0ea5e9", 900: "#0c4a6e", }, custom: { accent: "#ff6b6b", warning: "#feca57", }, },
spacing: { ...spacing, // Add custom spacing values xs: 2, // 2px xxl: 96, // 96px },};
// Use in components<View style={[ { backgroundColor: customTokens.colors.brand[500] }, { padding: customTokens.spacing.xxl }, ]}/>;
5. Theme-Based Overrides
Section titled “5. Theme-Based Overrides”Create theme-based style overrides:
import { platformStyle } from "@streamplace/components";
// Create theme-aware stylesconst createThemedStyles = (isDark: boolean) => ({ container: [bg.white, isDark && { backgroundColor: "#1a1a1a" }],
text: [text.gray[900], isDark && { color: "#ffffff" }],
border: [borders.color.gray[200], isDark && { borderColor: "#374151" }],});
function ThemedComponent({ isDark = false }) { const styles = createThemedStyles(isDark);
return ( <View style={styles.container}> <Text style={styles.text}>Themed content</Text> </View> );}
6. Component-Specific Style Systems
Section titled “6. Component-Specific Style Systems”For complex components, create dedicated style systems:
import { mergeStyles, atoms, bg, text, p, r } from "@streamplace/components";
const { layout } = atoms;
// Component-specific style systemconst cardStyles = { base: [ layout.flex.column, bg.white, r[3], p[6], { shadowColor: "#000", shadowOpacity: 0.1 }, ],
variants: { elevated: [{ shadowOffset: { width: 0, height: 4 } }], flat: [{ shadowOpacity: 0 }], outlined: [ { backgroundColor: "transparent" }, borders.width.thin, borders.color.gray[200], ], },
sizes: { sm: [p[4], r[2]], md: [p[6], r[3]], lg: [p[8], r[4]], },};
function Card({ variant = "elevated", size = "md", style, children }) { const cardStyle = mergeStyles( ...cardStyles.base, ...cardStyles.variants[variant], ...cardStyles.sizes[size], style, // Allow external style overrides );
return <View style={cardStyle}>{children}</View>;}
7. Global Style Overrides
Section titled “7. Global Style Overrides”For app-wide style overrides, create a style override system:
import { colors, spacing } from "@streamplace/components";
// Global style overridesconst globalOverrides = { // Override default colors colors: { primary: { ...colors.primary, 500: "#your-brand-color", }, },
// Override default spacing spacing: { ...spacing, // Make default padding larger 4: 20, // instead of 16 },
// Add custom shadows shadows: { card: { shadowColor: "#000", shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.25, shadowRadius: 3.84, elevation: 5, }, },};
// Use throughout your appexport { globalOverrides as customTheme };
8. Runtime Style Configuration
Section titled “8. Runtime Style Configuration”For dynamic style configuration:
import { responsiveValue } from "@streamplace/components";
// Runtime configurationconst styleConfig = { brandColor: "#your-color", borderRadius: 8, spacing: { small: 8, medium: 16, large: 24, }};
function ConfigurableComponent({ config = styleConfig }) { return ( <View style={[
## Theme Customization
ZeroCSS includes a comprehensive theme system that allows you to customize the default design tokens and create consistent theming across your app.
### ThemeProvider Setup
Wrap your app with the `ThemeProvider` to enable theming:
```tsximport { ThemeProvider } from "@streamplace/components";
function App() { return ( <ThemeProvider defaultTheme="system"> {/* Your app content */} </ThemeProvider> );}
Basic Theme Configuration
Section titled “Basic Theme Configuration”The ThemeProvider accepts several configuration options:
<ThemeProvider defaultTheme="system" // "light" | "dark" | "system" forcedTheme="dark" // Force a specific theme> <YourApp /></ThemeProvider>
Using Theme in Components
Section titled “Using Theme in Components”Access the current theme using the useTheme
hook:
// Option 1: Import from main componentsimport { useTheme } from "@streamplace/components";
// Option 2: Import from ZeroCSS namespaceimport * as zero from "@streamplace/components/zero";const { useTheme } = zero;
function ThemedComponent() { const { theme, isDark, setTheme } = useTheme();
return ( <View style={{ backgroundColor: theme.colors.background, borderColor: theme.colors.border, padding: theme.spacing[4], borderRadius: theme.borderRadius.md, }} > <Text style={{ color: theme.colors.text }}> Current theme: {isDark ? "Dark" : "Light"} </Text>
<Pressable onPress={() => setTheme(isDark ? "light" : "dark")}> <Text>Toggle Theme</Text> </Pressable> </View> );}
Creating Custom Themes
Section titled “Creating Custom Themes”You can create custom theme configurations by extending the base theme:
import { lightTheme, darkTheme } from "@streamplace/components";
// Custom light themeconst customLightTheme = { ...lightTheme, colors: { ...lightTheme.colors, primary: "#your-brand-color", background: "#fafafa", // Override any color tokens }, spacing: { ...lightTheme.spacing, // Add custom spacing values xs: 2, xxl: 96, },};
// Custom dark themeconst customDarkTheme = { ...darkTheme, colors: { ...darkTheme.colors, primary: "#your-brand-color-dark", background: "#0a0a0a", },};
Injecting Custom Themes into ThemeProvider
Section titled “Injecting Custom Themes into ThemeProvider”To use custom themes with the useTheme
hook, you need to create a custom
ThemeProvider wrapper:
import React, { createContext, useContext, useMemo, useState } from "react";import { useColorScheme } from "react-native";import { ThemeProvider as BaseThemeProvider, useTheme as useBaseTheme,} from "@streamplace/components";
// Create custom theme contextconst CustomThemeContext = createContext(null);
// Custom theme provider that injects your themesexport function CustomThemeProvider({ children, lightTheme: customLight, darkTheme: customDark, defaultTheme = "system",}) { const systemColorScheme = useColorScheme(); const [currentTheme, setCurrentTheme] = useState(defaultTheme);
// Determine active theme const activeTheme = useMemo(() => { const isDark = currentTheme === "dark" || (currentTheme === "system" && systemColorScheme === "dark");
return isDark ? customDark : customLight; }, [currentTheme, systemColorScheme, customLight, customDark]);
const value = { theme: activeTheme, isDark: activeTheme === customDark, currentTheme, setTheme: setCurrentTheme, toggleTheme: () => { setCurrentTheme((prev) => (prev === "light" ? "dark" : "light")); }, };
return ( <CustomThemeContext.Provider value={value}> <BaseThemeProvider defaultTheme={currentTheme}> {children} </BaseThemeProvider> </CustomThemeContext.Provider> );}
// Custom hook to access your custom themesexport function useCustomTheme() { const context = useContext(CustomThemeContext); if (!context) { throw new Error("useCustomTheme must be used within CustomThemeProvider"); } return context;}
Using Custom Themes in Your App
Section titled “Using Custom Themes in Your App”import { CustomThemeProvider, useCustomTheme } from "./path/to/your/theme";
// Define your custom themesconst myLightTheme = { colors: { primary: "#ff6b6b", background: "#ffffff", text: "#333333", // ... other colors }, spacing: { /* custom spacing */ }, // ... other tokens};
const myDarkTheme = { colors: { primary: "#ff8787", background: "#1a1a1a", text: "#ffffff", // ... other colors }, spacing: { /* custom spacing */ }, // ... other tokens};
// App setupfunction App() { return ( <CustomThemeProvider lightTheme={myLightTheme} darkTheme={myDarkTheme} defaultTheme="system" > <YourApp /> </CustomThemeProvider> );}
// Using custom theme in componentsfunction ThemedComponent() { const { theme, isDark, setTheme } = useCustomTheme();
return ( <View style={{ backgroundColor: theme.colors.background, padding: theme.spacing?.[4] || 16, }} > <Text style={{ color: theme.colors.text }}> Using custom {isDark ? "dark" : "light"} theme! </Text>
<Pressable onPress={() => setTheme(isDark ? "light" : "dark")}> <Text style={{ color: theme.colors.primary }}>Switch Theme</Text> </Pressable> </View> );}
Alternative: Theme Override Pattern
Section titled “Alternative: Theme Override Pattern”For simpler customization, you can override themes at the component level:
import { useTheme } from "@streamplace/components";// or: import * as zero from "@streamplace/components/zero";
function ComponentWithCustomTheme() { const { theme: baseTheme, isDark } = useTheme();
// Override specific theme values const customTheme = useMemo( () => ({ ...baseTheme, colors: { ...baseTheme.colors, primary: "#your-brand-color", background: isDark ? "#0a0a0a" : "#fafafa", }, }), [baseTheme, isDark], );
return ( <View style={{ backgroundColor: customTheme.colors.background, borderColor: customTheme.colors.primary, }} > <Text style={{ color: customTheme.colors.text }}> Custom themed component </Text> </View> );}
Theme-Aware Component Styles
Section titled “Theme-Aware Component Styles”Create components that automatically adapt to theme changes:
// Option 1: Import from main componentsimport { createThemedStyles } from "@streamplace/components";
// Option 2: Import from ZeroCSS namespaceimport * as zero from "@streamplace/components/zero";const { createThemedStyles } = zero;
const useButtonStyles = createThemedStyles((theme, styles, icons) => ({ primary: { backgroundColor: theme.colors.primary, borderRadius: theme.borderRadius.md, paddingHorizontal: theme.spacing[4], paddingVertical: theme.spacing[3], ...styles.shadow.sm, },
secondary: { backgroundColor: theme.colors.secondary, borderWidth: 1, borderColor: theme.colors.border, borderRadius: theme.borderRadius.md, paddingHorizontal: theme.spacing[4], paddingVertical: theme.spacing[3], },
text: { color: theme.colors.primaryForeground, fontSize: theme.typography.universal.body.fontSize, fontWeight: theme.typography.universal.body.fontWeight, },}));
function ThemedButton({ variant = "primary", children }) { const styles = useButtonStyles();
return ( <Pressable style={styles[variant]}> <Text style={styles.text}>{children}</Text> </Pressable> );}
Platform-Specific Theme Customization
Section titled “Platform-Specific Theme Customization”Customize themes for specific platforms:
import { Platform } from "react-native";import { colors } from "@streamplace/components";
const platformTheme = { colors: { primary: Platform.select({ ios: colors.ios.systemBlue, android: colors.android.materialBlue, default: colors.primary[500], }),
destructive: Platform.select({ ios: colors.ios.systemRed, android: colors.destructive[500], default: colors.destructive[500], }), },};
Runtime Theme Switching
Section titled “Runtime Theme Switching”Implement dynamic theme switching in your app:
import { useTheme } from "@streamplace/components";// or: import * as zero from "@streamplace/components/zero";
function ThemeToggler() { const { currentTheme, setTheme, toggleTheme } = useTheme();
return ( <View> <Text>Current: {currentTheme}</Text>
<Pressable onPress={() => setTheme("light")}> <Text>Light</Text> </Pressable>
<Pressable onPress={() => setTheme("dark")}> <Text>Dark</Text> </Pressable>
<Pressable onPress={() => setTheme("system")}> <Text>System</Text> </Pressable>
<Pressable onPress={toggleTheme}> <Text>Toggle</Text> </Pressable> </View> );}
Accessing Theme Outside Components
Section titled “Accessing Theme Outside Components”For utilities or functions that need theme access outside of React components:
import { lightTheme, darkTheme } from "@streamplace/components";// or: import * as zero from "@streamplace/components/zero";
// Utility function that uses themefunction createUtilityStyles(isDark = false) { const theme = isDark ? darkTheme : lightTheme;
return { container: { backgroundColor: theme.colors.background, padding: theme.spacing[4], }, text: { color: theme.colors.text, fontSize: theme.typography.universal.body.fontSize, }, };}
The theme system provides complete control over your app’s visual design while maintaining the convenience and consistency of ZeroCSS atomic utilities.
Streamplace ZeroCSS provides a powerful, consistent, and maintainable approach to styling React Native components. By leveraging atomic utilities and design tokens, you can build interfaces that are both beautiful and performant across all platforms.