Customize Theme
By default, all Pearl UI components inherit values from the default theme. In some scenarios, you might need to customize the theme to match your app's design requirements.
Pearl UI allows you to fully:
- Customize the theme tokens like colors, spacing, etc.
- Customize the component styles, changing the base styles, sizes, or variants.
#
Customizing theme tokensTo extend or override tokens in the default theme, import the extendTheme
function and add the keys you'd like to override. You can also add new values to the theme.
For example, if you'd like to update the colors in the theme to include your brand colors, here's what you'll do:
// 1. Import `extendTheme`import { extendTheme, ThemeProvider, Box } from "pearl-ui"
// 2. Call `extendTheme` and pass your custom valuesconst theme = extendTheme({ palette: { primary: { 100: "#123312", // ... 900: "#442441", },
tertiary: { 100: "#f7fafc", // ... 900: "#1a202c", }, },
spacing: { xxxs: 1, xxs: 2, xs:3, // ... xxxl: 98 }})
// 3. Pass the new theme to `ChakraProvider`<ThemeProvider theme={theme}> <App /></ThemeProvider>
// 4. Now you can use these colors in your componentsfunction Usage() { return <Box bg="tertiary.100" p="xxxs">I'm a tertiary box!</Box>}
#
Customizing component stylesCreating, managing, and customizing components in a scalable manner as your project evolves can be extremely challenging. It usually requires a lot of developer expertise and constant refactoring, which eventually reduce delivery speed for your application.
In order to deal with this, Pearl UI provides a rich styling API that allows you to style your components through the following approaches:
- Style Props: Add styles to a component by passing in style properties as component props.
<Box backgroundColor="neutral.100" width="40%" height={200} borderStyle="solid" borderWidth={2} borderColor="tomato" borderRadius="l"/>
- StyleSheets: The de facto approach for styling components in React Native.
import { StyleSheet } from "react-native";
<Box style={styles.box} />;
const styles = StyleSheet.create({ box: { flex: 1, padding: 24, backgroundColor: "#eaeaea", },});
- Component Style Config: This approach is heavily inspired from the
styleConfig
API implemented in Chakra UI. It provides a consistent API that allows component styling through a single JSON file, thus making it easy to understand and maintain.
<Button size="s" variant="outline" />
#
Component Style ConfigThe Component Config API provides a standard format for specifying styles for a component that scales with your project. The main idea is most components have default or base styles, styles for different sizes (e.g. small, medium, large), and styles for different visual variants ((e.g. outline, solid, ghost)), and a defaults
to denote the default size or variant.
#
Atomic component configAn atomic component is analogous to an Atom in the Atomic Design methodology. Most components available in Pearl UI today are atomic components (e.g. Text, Spinner, Icon, etc.), and use the useAtomicComponentConfig hook to enable the component style config.
The component config format for an atomic component is as follow:
export default { // Base styles that are common to all sizes/variants baseStyle: {}, // Styles for the size variations sizes: {}, // Styles for the visual style variations variants: {}, // The default `size` or `variant` values defaults: {},};
An example of the atomic component config applied to the Icon component is given below:
const newIconConfig = { // The styles all icons have in common baseStyle: { color: { light: "neutral.900", // <-- The color of the icon when the app is in light mode dark: "neutral.100", // <-- The color of the icon when the app is in dark mode }, }, // Four sizes: s, m, l, and xl sizes: { s: { size: 15, // <-- Not a style prop, so it is passed directly to the ExpoIcons component used in the Pearl UI Icon component }, m: { size: 20, }, l: { size: 25, }, xl: { size: 30, }, }, // Three variants: neutral, primary, and secondary variants: { neutral: {}, // <-- Since this is empty, it uses the baseStyle configuration primary: { color: "primary.500", // <-- Overwrites the baseStyle configuration to always keep the color as 'primary.500' }, secondary: { color: "secondary.500", // <-- Overwrites the baseStyle configuration to always keep the color as 'secondary.500' }, }, // The default size and variant values defaults: { size: "m", variant: "neutral", },};
For the final step, update the theme to include this new component configuration as follows:
import { extendTheme } from "pearl-ui";
const theme = extendTheme({ components: { Icon: newIconConfig, },});
That's all you have to do! Now, when you use the Icon component, these updates will be automatically applied:
<Box flexDirection="row" justifyContent="space-between"> <Icon iconFamily="Entypo" iconName="cup" size="s" variant="neutral" /> <Icon iconFamily="Entypo" iconName="cup" size="m" variant="primary" /> <Icon iconFamily="Entypo" iconName="cup" size="xl" variant="secondary" /></Box>
Light Mode
Dark Mode
#
Molecular component configA molecular component is analogous to a Molecule in the Atomic Design methodology. Many components used in an actual app are molecular components (eg. Button, Datepicker, Modal, etc), and use the useMolecularComponentConfig hook to enable the component style config.
The component config format for a molecular component is as follow:
export default { // The parts of the component parts: [], // Base styles that are common to all sizes/variants baseStyle: {}, // Styles for the size variations sizes: {}, // Styles for the visual style variations variants: {}, // The default `size` or `variant` values defaults: {},};
An example of a molecular component config applied to the Button component is given below:
const newButtonConfig = { // Define the parts you want to use parts: ["root", "text", "spinner", "icon"], // The baseStyle config for all parts baseStyle: { // The styles all root parts would have in common root: { margin: "xxs", justifyContent: "center", alignItems: "center", }, }, // Two sizes: s and m sizes: { // Styles for all parts when the molecular component has size 's' s: { root: { py: "xs", px: "xs", borderRadius: "s", }, text: { variant: "btn3", }, spinner: { size: "m", }, icon: { size: "m", }, }, // Styles for all parts when the molecular component has size 'm' m: { root: { py: "s", px: "s", borderRadius: "m", }, text: { variant: "btn2", }, spinner: { size: "m", }, icon: { size: "m", }, }, }, // Two variants: filled and outline variants: { // Styles for all parts when the molecular component has variant 'filled' opaque: { root: { backgroundColor: "primary.500", }, text: { color: "neutral.100" }, spinner: { color: "neutral.100", }, icon: { color: "neutral.100", }, }, // Styles for all parts when the molecular component has variant 'outline' hollow: { root: { backgroundColor: { light: "neutral.100", dark: "neutral.800", }, borderWidth: 1, borderColor: "primary.500", }, text: { color: "primary.500" }, spinner: { color: "primary.500", }, icon: { color: "primary.500", }, }, }, // The default size and variant values for the molecular component defaults: { size: "m", variant: "opaque", },};
For the final step, update the theme to include this new component configuration as follows:
import { extendTheme } from "pearl-ui";
const theme = extendTheme({ components: { Button: newButtonConfig, },});
That's it! Now, when you use the Button component, these updates will be automatically applied:
<Button size="s" variant="opaque">Small Opaque button</Button><Button size="m" variant="hollow">Medium Hollow button</Button>