Paramount
Edit page
IntroductionCustomizationLook and FeelComponentsOptionsLayout
Components
ContributingReadme

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'
<ThemeProvider
value={{
// Colors
colors: Colors;
fills: Fills;
// Layout
layout: Layout;
spacing: SpacingSizes;
// Typography
fontFamilies: FontFamilies;
fontWeights: FontWeights;
headingSizes: HeadingSizes;
paragraphSizes: ParagraphSizes;
textSizes: TextSizes;
// Elevations
elevations: Elevations;
// Controls - Buttons, Pickers, Inputs etc.
controlPaddings: ControlSizes;
controlHeights: ControlSizes;
controlBorderRadius: ControlSizes;
// Containers
containerShapes: 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 (
<Button
color={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 Web
const 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,
};