Theme Object
Learn about the theme object and how it's used in the code.
- what are the different properties of the theme object
- how to properly access the theme object in the code
Overview
The theme object defines different visual aspects of our website, for example the default set of colors, typography, breakpoints, and more.
Apart from being used in the code by different page elements, the theme object is also integrated with different editors that are available in the Page Builder’s application, like page or block editor.
For example, colors or different typography options defined in the theme object are automatically picked up by these editors, enabling users to select them while building content and ensuring everything stays visually consistent.

By default, the theme object is exported from the apps/theme/theme.ts
file, and it looks like the following:
// Parts of code removed for brevity.
import { createTheme } from "@webiny/app-theme";
import { CSSObject } from "@emotion/react";
// Breakpoints (desktop, tablet, mobile).
export const breakpoints = {
desktop: "@media (max-width: 4000px)",
tablet: "@media (max-width: 991px)",
"mobile-landscape": "@media (max-width: 767px)",
"mobile-portrait": "@media (max-width: 478px)"
};
// Colors.
export const colors = {
color1: "#fa5723", // Primary.
color2: "#00ccb0", // Secondary.
color3: "#0a0a0a", // Text primary.
color4: "#616161", // Text secondary.
color5: "#eaecec", // Background.
color6: "#ffffff" // White background.
};
// Fonts.
export const fonts = {
font1: "'IBM Plex Sans', sans-serif;", // Primary.
font2: "'Lato', sans-serif;" // Secondary.
};
// Border radius.
export const borderRadius = 4;
// Typography.
// Code removed for brevity. Shown in the Typography section below.
// Buttons.
const buttons = (overrides: CSSObject) => ({
// Code removed for brevity.
});
// Theme object.
const theme = createTheme({
breakpoints,
styles: {
colors,
typography,
elements: {
document: {
a: { color: colors.color1 },
b: { fontWeight: "bold" },
i: { fontStyle: "italic" }
},
button: {
default: buttons({ background: colors.color5, color: colors.color3 }),
primary: buttons({ background: colors.color1, color: colors.color6 }),
secondary: buttons({ background: colors.color2, color: colors.color6 }),
outlinePrimary: buttons({
border: `2px solid ${colors.color1}`,
color: colors.color1
}),
outlineSecondary: buttons({
border: `2px solid ${colors.color2}`,
color: colors.color2
}),
simple: buttons({
color: colors.color1,
"&:hover": { transform: "translateY(-1px)" }
})
}
}
}
});
export default theme;
In the following text, we cover all the different properties of which the theme object consists of.
Properties
Breakpoints
Via the breakpoints
object, the theme object defines four available breakpoints:
- desktop
- tablet
- mobile (landscape orientation)
- mobile (portrait orientation)
Note that the property names of these breakpoints (desktop
, tablet
, mobile-landscape
, mobile-portrait
) should not be changed. But, the assigned media queries can be adjusted and new ones can be introduced, if need be.
Colors
Via the styles.colors
object, the theme object defines theme colors, where property names represent the IDs of colors and values respective color codes.
The IDs of colors don’t follow any naming convention. Upon introducing new colors, IDs like primaryColor
or myCustomColor
will work as well.
Typography
Via the styles.typography
object, the theme object defines theme typography. Unlike with breakpoints and colors, property names here represent the typography categories, and values array of different typography variants. For example, in the following code snippet, we can see six different heading variants being defined:
// (...)
// Typography.
const headings = {
fontFamily: fonts.font2,
color: colors.color3,
WebkitFontSmoothing: "antialiased"
};
const paragraphs = {
fontFamily: fonts.font1,
color: colors.color3,
fontWeight: 400,
lineHeight: 1.35,
WebkitFontSmoothing: "antialiased"
};
export const typography = {
// Six heading variants (levels of headings).
headings: [
{
id: "heading1",
name: "Heading 1",
tag: "h1",
styles: { ...headings, fontWeight: "bold", fontSize: 48 }
},
{
id: "heading2",
name: "Heading 2",
tag: "h2",
styles: { ...headings, fontSize: 36 }
},
{
id: "heading3",
name: "Heading 3",
tag: "h3",
styles: { ...headings, fontSize: 30 }
},
{
id: "heading4",
name: "Heading 4",
tag: "h4",
styles: { ...headings, fontSize: 24 }
},
{
id: "heading5",
name: "Heading 5",
tag: "h5",
styles: { ...headings, fontSize: 20 }
},
{
id: "heading6",
name: "Heading 6",
tag: "h6",
styles: { ...headings, fontSize: 18, lineHeight: "1.75rem" }
}
]
// Below we have three more typography categories: paragraphs, quotes, and lists.
};
// (...)
Every typography variant consists of the following properties:
Property | Description |
---|---|
id | A unique ID of the typography variant. Like with colors, typography IDs don’t follow any naming convention. Upon introducing new typography, IDs like primaryTypography or myCustomTypography will work as well. |
name | A human-readable name of the typography variant. Will be shown in different Page Builder editors like page or block editor. |
tag | A HTML tag that will be used to render the typography variant. |
styles | A CSS object that defines the visual appearance of the typography variant. |
Note that, when accessing the theme object and different typography variants, to make it easier, we can leverage the
special stylesById
getter function. More on this below, in the Accessing the Theme
Object section.
Page Elements
Respectively, the styles.elements
object enables defining and overriding styles for new and existing page elements. Like with colors and typography, property names represent the IDs of page elements, and values respective CSS rules that define them visually.
By default, the property contains styles for default document
and
button
page elements, but note that styles for custom ones can be added here as well.
Accessing the Theme Object
While styling page layouts or custom page elements, the theme object can be accessed in order to use the styling rules defined in it. To access the theme object, we rely on Emotion’s suggested approach, which is through the React context.The easiest way to access the theme object is via styled components, like in the following example:
import * as React from "react";
import styled from "@emotion/styled";
const SomeDiv = styled.div`
background-color: ${props => props.theme.styles.colors["color5"]};
height: 100px;
`;
As we can see, the theme
object is available via the props
argument of the styled component’s template literal function. This means that we can access any of the theme object’s properties, like styles.colors
, styles.typography
or styles.elements
.
Note that the theme object should not be accessed by directly importing the apps/theme/theme.ts
file. This can
lead to issues in multi-theme projects, where the theme object is not the same for all themes.
Multiple examples of accessing the theme object can be found in the Static page page layout code that’s included by default in all new projects. The code is located in the apps/theme/layouts/pages
code folder.
Accessing Typography Variants
When accessing typography variants, we can leverage the special stylesById
getter function, like in the following example:
import * as React from "react";
import styled from "@emotion/styled";
const SomeDiv = styled.div`
${props => props.theme.styles.typography.paragraphs.stylesById("paragraph1")};
height: 100px;
width: 200px;
`;
As we can see, the stylesById
getter function accepts a typography variant ID as an argument, and returns a CSS object that defines the visual appearance of the typography variant. This way, we can easily access different typography variants, without having to manually traverse the styles.typography
object.
Custom Page Elements
If needed, theme object can also be accessed when creating custom page elements, via the useRenderer
React hook. For example:import React from "react";
import { createRenderer } from "~/createRenderer";
import { useRenderer } from "~/hooks/useRenderer";
export type CustomPageElementRenderer = ReturnType<typeof createCustomPageElement>;
export const createCustomPageElement = () => {
return createRenderer(() => {
// Accessing the theme object via the useRenderer hook.
const { theme } = useRenderer();
return (
// Using color1 from the theme object.
<div style={{ color: theme.styles.colors["color1"] }}>Custom page element.</div>
);
});
};
Most often, styles for custom page elements are introduced via one or more standalone Emotion styled components.
FAQ
When Defining Custom Theme, Should I Create a Copy of the Theme or Can I Just Override the Values I Need?
In general, it depends on your needs and personal preference. There’s nothing wrong with simply overriding the values you need.
Is Having Multiple Themes Supported Out of the Box?
Out of the box, every Webiny project starts with a single theme (the one located in the apps/theme