Customization
Paramount UI provides full customizability of components.
Look and Feel
For general look and feel customization, you can tweak the tokens in the theme. Pass a Theme
object to ThemeProvider
.
For all available options, refer to Options
import { ThemeProvider } from 'paramount-ui'<ThemeProvidervalue={{// Colorscolors: Colors;fills: Fills;// Layoutlayout: Layout;spacing: SpacingSizes;// TypographyfontFamilies: FontFamilies;fontWeights: FontWeights;headingSizes: HeadingSizes;paragraphSizes: ParagraphSizes;textSizes: TextSizes;// Elevationselevations: Elevations;// Controls - Buttons, Pickers, Inputs etc.controlPaddings: ControlSizes;controlHeights: ControlSizes;controlBorderRadius: ControlSizes;// ContainerscontainerShapes: ContainerShapes;}}>...</ThemeProvider>
You can also import theme values from a convenience hook useTheme
const MyComponent = () => {const { colors, fills, ...theme } = useTheme();...}
Components
For more granular level of component customization, we use "Overrides" approach inspired by Base UI by Uber
Overrides can be applied either per component or from ThemeProvider
Per component
Components with more than one React Node, expose overrides
prop, through which you can customize the style or even its children props. Each component has a corresponding Overrides API
section, through which you can see available options.
For example (taken from Picker.tsx
):
import { Button } from 'paramount-ui';const CustomButton = () => {const { isSelected, value, onSelect } = props;const theme = useTheme();return (<Buttoncolor={isSelected ? 'primary' : 'default'}overrides={{Touchable: {style: {backgroundColor: isSelected ? 'white' : 'transparent',paddingLeft: 0,paddingRight: 0,},},Title: {style: {color: isSelected? theme.colors.text.primary: theme.colors.text.muted,},},}}title={typeof value === 'string' ? value : 'Invalid value'}onPress={onSelect}/>);};
From ThemeProvider
In the same ThemeProvider
as above, use components
option to apply the overrides
export interface ThemeOverrides {Alert: Overrides<any, AlertOverrides>;Avatar: Overrides<any, AvatarOverrides>;Badge: Overrides<any, BadgeOverrides>;Button: Overrides<any, ButtonOverrides>;Checkbox: Overrides<any, CheckboxOverrides>;Collapsible: Overrides<any, CollapsibleOverrides>;Column: ColumnOverride;Container: ContainerOverride;Counter: Overrides<any, CounterOverrides>;Dialog: Overrides<any, DialogOverrides>;Divider: DividerOverride;Drawer: Overrides<any, DrawerOverrides>;FormField: Overrides<any, FormFieldOverrides>;Heading: HeadingOverride;Label: Overrides<any, LabelOverrides>;ListItem: Overrides<any, ListItemOverrides>;ListPicker: Overrides<any, ListPickerOverrides<any>>;NativePicker: Overrides<any, NativePickerOverrides>;Overlay: OverlayOverride;Popover: Overrides<any, PopoverOverrides>;Positioner: Overrides<any, PositionerOverrides>;ProgressBar: Overrides<any, ProgressBarOverrides>;Rating: Overrides<any, RatingOverrides>;Row: RowOverride;Slider: Overrides<any, SliderOverrides>;Spacing: SpacingOverride;Switch: Overrides<any, SwitchOverrides>;Picker: Overrides<any, PickerOverrides<any, any, any>>;Text: TextOverride;TextInput: Overrides<any, TextInputOverrides>;WheelPicker: Overrides<any, WheelPickerOverrides<any>>;}
Options
These are all the available theme configuration options, as well as their default values
const controlPaddings: ControlSizes = {small: 8,medium: 16,large: 24,};const controlHeights: ControlSizes = {small: 40,medium: 48,large: 56,};const controlBorderRadius: ControlSizes = {small: 4,medium: 4,large: 4,};const spacing: { [size in SpacingSize]: number } = {xsmall: 4,small: 8,medium: 16,large: 24,xlarge: 32,xxlarge: 40,xxxlarge: 48,};const colors: Colors = {background: {base: 'white',content: 'white',greyLight: palette.neutral.lightest,greyDefault: '#F5F6F7',greyDark: palette.neutral.light,primaryLight: palette.teal.lightest,primaryDefault: palette.teal.base,primaryDark: palette.teal.dark,secondaryLight: palette.orange.lightest,secondaryDefault: palette.orange.base,secondaryDark: palette.orange.dark,dangerLight: palette.red.lightest,dangerDefault: palette.red.base,dangerDark: palette.red.dark,infoLight: palette.blue.lightest,infoDefault: palette.blue.base,infoDark: palette.blue.dark,successLight: palette.green.lightest,successDefault: palette.green.base,successDark: palette.green.dark,warningLight: palette.orange.lightest,warningDefault: palette.orange.base,warningDark: palette.orange.dark,},border: {default: palette.neutral.light,primary: palette.teal.darkest,secondary: palette.orange.darkest,danger: palette.red.darkest,info: palette.blue.darkest,success: palette.green.darkest,warning: palette.orange.darkest,},button: {disabled: palette.neutral.light,disabledText: palette.neutral.darkest,default: palette.neutral.lightest,defaultText: palette.neutral.darkest,primary: palette.teal.base,primaryText: 'white',secondary: palette.orange.base,secondaryText: 'white',danger: palette.red.base,dangerText: 'white',},text: {link: palette.teal.darkest,default: palette.neutral.darkest,muted: palette.neutral.dark,white: 'white',selected: 'white',primary: palette.teal.darkest,secondary: palette.orange.darkest,danger: palette.red.darkest,info: palette.blue.darkest,success: palette.green.darkest,warning: palette.orange.darkest,},};const elevations: Elevations = [{elevation: 0,shadowColor: palette.neutral.dark,shadowOffset: { width: 0, height: 0 },shadowOpacity: 0,shadowRadius: 0,},{elevation: 1,shadowColor: palette.neutral.dark,shadowOffset: { width: 1, height: 1 },shadowOpacity: 0.15,shadowRadius: 8,},{elevation: 2,shadowColor: palette.neutral.dark,shadowOffset: { width: 2, height: 2 },shadowOpacity: 0.2,shadowRadius: 10,},{elevation: 3,shadowColor: palette.neutral.dark,shadowOffset: { width: 3, height: 3 },shadowOpacity: 0.25,shadowRadius: 12,},{elevation: 4,shadowColor: palette.neutral.dark,shadowOffset: { width: 4, height: 4 },shadowOpacity: 0.3,shadowRadius: 8,},{elevation: 5,shadowColor: palette.neutral.dark,shadowOffset: { width: 5, height: 5 },shadowOpacity: 0.35,shadowRadius: 8,},];const fills: Fills = {solid: {neutral: {backgroundColor: palette.neutral.base,color: 'white',},blue: {backgroundColor: palette.blue.base,color: 'white',},red: {backgroundColor: palette.red.base,color: 'white',},orange: {backgroundColor: palette.orange.base,color: 'white',},yellow: {backgroundColor: palette.yellow.base,color: palette.yellow.darkest,},green: {backgroundColor: palette.green.base,color: 'white',},teal: {backgroundColor: palette.teal.base,color: 'white',},purple: {backgroundColor: palette.purple.base,color: 'white',},},subtle: {neutral: {backgroundColor: palette.neutral.light,color: palette.neutral.darkest,},blue: {backgroundColor: palette.blue.light,color: palette.blue.darkest,},red: {backgroundColor: palette.red.light,color: palette.red.darkest,},orange: {backgroundColor: palette.orange.light,color: palette.orange.darkest,},yellow: {backgroundColor: palette.yellow.light,color: palette.yellow.darkest,},green: {backgroundColor: palette.green.light,color: palette.green.darkest,},teal: {backgroundColor: palette.teal.light,color: palette.teal.darkest,},purple: {backgroundColor: palette.purple.light,color: palette.purple.darkest,},},};// Use system font on the Webconst fontFamilies: FontFamilies =Platform.OS === 'web'? {heading: `"SF UI Display", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,mono: `"SF Mono", "Monaco", "Inconsolata", "Fira Mono", "Droid Sans Mono", "Source Code Pro", monospace`,text: `"SF UI Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,}: {heading: 'System',mono: 'System',text: 'System',};const fontWeights: FontWeights = {bold: 'bold',light: '300',normal: 'normal',};const headingSizes: HeadingSizes = {xxxlarge: {fontSize: 35,letterSpacing: -0.2,lineHeight: 40,},xxlarge: {fontSize: 29,letterSpacing: -0.2,lineHeight: 32,},xlarge: {fontSize: 24,letterSpacing: -0.07,lineHeight: 28,},large: {fontSize: 20,letterSpacing: -0.07,lineHeight: 24,},medium: {fontSize: 16,letterSpacing: -0.05,lineHeight: 20,},small: {fontSize: 14,letterSpacing: -0.05,lineHeight: 20,},};const paragraphSizes: ParagraphSizes = {small: {fontSize: 14,lineHeight: 24,},medium: {fontSize: 16,lineHeight: 21,},large: {fontSize: 18,lineHeight: 18,},};const textSizes: TextSizes = {large: {fontSize: 20,},medium: {fontSize: 16,},small: {fontSize: 14,},xsmall: {fontSize: 12,},};const containerShapes: ContainerShapes = {circle: {borderRadius: 999,},pill: {borderRadius: 999,},rounded: {borderRadius: controlBorderRadius.medium,},roundedBottom: {borderBottomLeftRadius: controlBorderRadius.medium,borderBottomRightRadius: controlBorderRadius.medium,},roundedLeft: {borderBottomLeftRadius: controlBorderRadius.medium,borderTopLeftRadius: controlBorderRadius.medium,},roundedRight: {borderBottomRightRadius: controlBorderRadius.medium,borderTopRightRadius: controlBorderRadius.medium,},roundedTop: {borderTopLeftRadius: controlBorderRadius.medium,borderTopRightRadius: controlBorderRadius.medium,},square: {borderRadius: 0,},};export const layout: Layout = {breakpoints: {small: 480,medium: 768,large: 992,xlarge: 1200,},containerSizes: {small: 540,medium: 720,large: 960,xlarge: 1200,},gridColumnCount: 12,gutterWidth: 32,};export const defaultTheme: Theme = {colors,fills,spacing,layout,fontFamilies,fontWeights,headingSizes,paragraphSizes,textSizes,elevations,controlBorderRadius,controlHeights,controlPaddings,containerShapes,};