useAppTheme
React hook that provides access to the current theme values throughout your application. This hook is the primary way to access colors, spacing, typography, and other theme properties in your components.
Quick Example
import React from "react";
import { StyleSheet, View } from "react-native";
import { useAppTheme } from "@ovok/mobile";
import { Text } from "react-native-paper";
// Static styles outside component
const styles = StyleSheet.create({
container: {
flex: 1,
},
card: {
borderWidth: 1,
borderRadius: 8,
},
});
export const ThemedComponent = () => {
const theme = useAppTheme();
return (
<View
style={[
styles.container,
{
backgroundColor: theme.colors.background,
padding: theme.spacing(4),
},
]}
>
<View
style={[
styles.card,
{
backgroundColor: theme.colors.surface,
borderColor: theme.colors.outline,
padding: theme.spacing(3),
borderRadius: theme.borderRadius(2),
},
]}
>
<Text
variant="titleMedium"
style={{
color: theme.colors.primary,
marginBottom: theme.spacing(2),
}}
>
Healthcare Dashboard
</Text>
<Text style={{ color: theme.colors.onSurface }}>
Patient vital signs monitoring
</Text>
</View>
</View>
);
};
Hook Signature
const theme: AppTheme = useAppTheme();
Returns
The hook returns an AppTheme object containing:
| Property | Type | Description |
|---|---|---|
colors | AppTheme["colors"] | Complete color palette |
spacing | (value: number) => number | Spacing function with multiplier |
borderRadius | (value: number) => number | Border radius function with multiplier |
roundness | number | Base border radius value |
dark | boolean | Whether dark mode is enabled |
Plus all properties from React Native Paper's MD3Theme.
Theme Properties
Colors
Access to complete color system including Material Design 3 colors and custom healthcare colors:
const theme = useAppTheme();
// Material Design 3 colors
theme.colors.primary; // Primary brand color
theme.colors.secondary; // Secondary brand color
theme.colors.tertiary; // Tertiary brand color
theme.colors.surface; // Surface background
theme.colors.background; // Main background
theme.colors.onSurface; // Text on surface
theme.colors.onBackground; // Text on background
// Healthcare semantic colors
theme.colors.success; // Success/healthy states
theme.colors.error; // Error/critical states
theme.colors.warning; // Warning/attention states
// Extended color palettes
theme.colors.blue[600]; // Specific blue shade
theme.colors.green[500]; // Specific green shade
theme.colors.red[700]; // Specific red shade
// ... and more color families
Spacing Function
Generate consistent spacing values using the configured multiplier:
const theme = useAppTheme();
// Usage patterns
<View
style={{
padding: theme.spacing(4), // 16px (with default 4px multiplier)
marginBottom: theme.spacing(3), // 12px
gap: theme.spacing(2), // 8px
}}
>
Border Radius Function
Generate consistent border radius values:
const theme = useAppTheme();
// Usage patterns
<View
style={{
borderRadius: theme.borderRadius(2), // 8px (with default 4px multiplier)
borderRadius: theme.borderRadius(3), // 12px
borderRadius: theme.borderRadius(4), // 16px
}}
>
Usage Patterns
Component Styling
import React from "react";
import { StyleSheet, View } from "react-native";
import { useAppTheme } from "@ovok/mobile";
import { Text, Button } from "react-native-paper";
// Static styles outside component - performance optimization
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
card: {
borderWidth: 1,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
});
export const StyledCard = ({ title, children, onPress }) => {
const theme = useAppTheme();
return (
<View
style={[
styles.card,
{
backgroundColor: theme.colors.surface,
borderColor: theme.colors.outline,
shadowColor: theme.colors.shadow,
padding: theme.spacing(4),
borderRadius: theme.borderRadius(3),
marginBottom: theme.spacing(3),
},
]}
>
<Text
variant="titleLarge"
style={{
color: theme.colors.onSurface,
marginBottom: theme.spacing(3),
}}
>
{title}
</Text>
{children}
<Button
mode="contained"
onPress={onPress}
style={{
marginTop: theme.spacing(3),
borderRadius: theme.borderRadius(2),
}}
buttonColor={theme.colors.primary}
>
Action
</Button>
</View>
);
};
Healthcare Status Colors
import React from "react";
import { useAppTheme } from "@ovok/mobile";
import { Text } from "react-native-paper";
export const VitalSignDisplay = ({ value, status, unit }) => {
const theme = useAppTheme();
const getStatusColor = (status: string) => {
switch (status) {
case "normal":
return theme.colors.success;
case "warning":
return theme.colors.warning;
case "critical":
return theme.colors.error;
default:
return theme.colors.onSurface;
}
};
return (
<Text
variant="headlineMedium"
style={{
color: getStatusColor(status),
fontWeight: "bold",
}}
>
{value} {unit}
</Text>
);
};
Dynamic Color Palettes
import React from "react";
import { useAppTheme } from "@ovok/mobile";
export const PaletteDisplay = ({ colorFamily }) => {
const theme = useAppTheme();
const colorShades = [
25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000,
];
return (
<View style={{ flexDirection: "row", flexWrap: "wrap" }}>
{colorShades.map((shade) => (
<View
key={shade}
style={{
width: 50,
height: 50,
backgroundColor: theme.colors[colorFamily][shade],
margin: theme.spacing(1),
borderRadius: theme.borderRadius(1),
}}
/>
))}
</View>
);
};
Responsive Layout
import React from "react";
import { useAppTheme } from "@ovok/mobile";
import { useWindowDimensions } from "react-native";
export const ResponsiveGrid = ({ children }) => {
const theme = useAppTheme();
const { width } = useWindowDimensions();
const isTablet = width > 768;
const columns = isTablet ? 3 : 2;
const spacing = theme.spacing(isTablet ? 4 : 3);
return (
<View
style={{
flexDirection: "row",
flexWrap: "wrap",
padding: spacing,
gap: spacing,
}}
>
{children}
</View>
);
};
Performance Optimization
Memoizing Theme-Dependent Values
For expensive calculations, memoize theme-dependent values:
import React from "react";
import { useAppTheme } from "@ovok/mobile";
export const ComplexComponent = () => {
const theme = useAppTheme();
// Memoize expensive style calculations
const complexStyles = React.useMemo(
() => ({
shadow: {
shadowColor: theme.colors.shadow,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.15,
shadowRadius: 8,
elevation: 6,
},
gradient: {
// Complex gradient calculations
backgroundColor: theme.colors.surface,
borderColor: theme.colors.outline,
},
}),
[theme.colors.shadow, theme.colors.surface, theme.colors.outline],
);
return (
<View style={[complexStyles.shadow, complexStyles.gradient]}>
{/* Component content */}
</View>
);
};
Avoiding Unnecessary Re-renders
import React from "react";
import { useAppTheme } from "@ovok/mobile";
// ✅ Good - Extract stable parts
const StaticChild = React.memo(() => {
return <Text>This doesn't need theme access</Text>;
});
export const OptimizedComponent = () => {
const theme = useAppTheme();
// ✅ Good - Only theme-dependent parts access theme
return (
<View style={{ backgroundColor: theme.colors.background }}>
<StaticChild />
<Text style={{ color: theme.colors.primary }}>
This needs theme colors
</Text>
</View>
);
};
Common Patterns
Theme-Aware Icon Colors
import React from "react";
import { useAppTheme } from "@ovok/mobile";
import { IconButton } from "react-native-paper";
export const ThemedIconButton = ({ icon, onPress, variant = "primary" }) => {
const theme = useAppTheme();
const iconColor = {
primary: theme.colors.primary,
success: theme.colors.success,
error: theme.colors.error,
surface: theme.colors.onSurface,
}[variant];
return (
<IconButton
icon={icon}
iconColor={iconColor}
onPress={onPress}
style={{
borderRadius: theme.borderRadius(2),
}}
/>
);
};
Conditional Dark Mode Styling
import React from "react";
import { useAppTheme } from "@ovok/mobile";
export const DarkModeAwareComponent = () => {
const theme = useAppTheme();
return (
<View
style={{
backgroundColor: theme.dark
? theme.colors.surface
: theme.colors.background,
borderColor: theme.dark
? theme.colors.outline
: theme.colors.outlineVariant,
borderWidth: 1,
padding: theme.spacing(4),
borderRadius: theme.borderRadius(2),
}}
>
<Text style={{ color: theme.colors.onSurface }}>
Content adapts to dark/light mode
</Text>
</View>
);
};
Form Styling
import React from "react";
import { useAppTheme } from "@ovok/mobile";
import { TextInput } from "react-native-paper";
export const ThemedForm = () => {
const theme = useAppTheme();
return (
<View
style={{
padding: theme.spacing(4),
gap: theme.spacing(3),
}}
>
<TextInput
label="Patient Name"
mode="outlined"
style={{
backgroundColor: theme.colors.surface,
}}
theme={{
colors: {
primary: theme.colors.primary,
outline: theme.colors.outline,
},
}}
/>
<TextInput
label="Medical Record Number"
mode="outlined"
style={{
backgroundColor: theme.colors.surface,
}}
/>
</View>
);
};
TypeScript Integration
The hook is fully typed and provides excellent IntelliSense support:
import { useAppTheme } from "@ovok/mobile";
export const TypedComponent = () => {
const theme = useAppTheme(); // Type: AppTheme
// Full type safety and autocompletion
theme.colors.primary; // string
theme.spacing(4); // number
theme.borderRadius(2); // number
theme.dark; // boolean
// Extended color palettes with type safety
theme.colors.blue[600]; // string
theme.colors.green[500]; // string
};
Related Components
- ThemeProvider - Provider component that supplies theme context
- Colors - Color system and palette definitions