The default Catalyst theme is built on a design system of modern React components for use in composable websites, built and maintained by BigCommerce.
This component system is designed specifically for ecommerce, providing beautiful, out-of-the-box UI for every part of the commerce experience. The library includes general, low-level components like buttons and accordions, as well as orchestrating these lower level components into more sophisticated presentations like product cards, product lists, and a site header.
The component library leverages modern patterns and the latest features of Next.js, and it is optimized for fast performance. The clean, practical prop interfaces of its components make them flexible and reusable in any context where they’re needed within your UI.
The look and feel of your storefront is easily style-able without the need for modifying component code. However, all theme components are also included directly in your project, ready to be customized to suit your own requirements.
The theme components are found in vibes/soul within your Catalyst project. This includes several major sub-sections:
Tailwind CSS is a popular CSS framework that enables rapid and reliable styling and visual layouts with a system of utility classes.
With Tailwind, instead of writing raw CSS, you chain together utility classes to accomplish the styling you need, as in this example from vibes/soul/sections/cart/index.tsx:
Tailwind is used by Next.js by default, and Catalyst components fully embrace Tailwind styling.
The Tailwind styles used throughout your theme components apply a consistent look and feel through a set of standardized values for text styles, font sizes, and color palette. It’s easy to customize the theme of your storefront without changing the basic structure and behavior of its components, using Tailwind and CSS configuration.
tailwind.config.js. You have a great deal of flexibility for adjusting your storefront’s theme simply by modifying these vars.next/font/google. The CSS variables applied to each font family here are utilized for standard font styles in the Tailwind config.Makeswift Style Customization
In your own codebase, you may notice that globals.css doesn’t define all the CSS variables used in tailwind.config.js. Color values, for example, are not defined here.
With Makeswift integrated, many hard-coded CSS variables are replaced with common color and font styles defined in the builder. These can then be applied to the properties of specific component types, allowing the storefront-wide look and feel to be modified without touching a line of code.
Explore more details about managing global styles in Makeswift Core.
Try practicing the use of global styles and configuration to modify your Catalyst theme.
globals.css to change the value of --font-size-base to a larger or smaller value.Note in tailwind.config.js where the CSS variable is used: for the fontSize.base configuration. A Tailwind text size class expressed as text-base should reflect this config. You can observe where this very class is used in the definition of the Button component (in the theme directory, in primitives/button/index.tsx).
fontSize value in tailwind.config.js, which can have an arbitrary key:Button component is defined and replace occurrences of text-base with text-2xs.To follow the typical Catalyst pattern, you can take this further by establishing a global CSS variable for this size in app/globals.css, and reference this in your Tailwind config.
Theme components implement a number of specialized CSS variables that can be used to control the general look and feel of those components, globally or in an isolated context.
This example can be seen in vibes/soul/primitives/card/index.tsx:
Taking --card-border-radius as an example, the Card component will fall back to a default if this CSS variable is not set but will use its value otherwise. You can take advantage of this in two ways:
--card-border-radius globally.app/globals.css.app/globals.css will have no effect.--card-border-radius directly on an ancestor element in specific context, affecting only a Card in that context.Explore more details about the process of theming components with Makeswift in Makeswift Core.
Many components include multiple variants.
See an example in the simple Button component (vibes/soul/primitives/button/index.tsx). This component defines “primary”, “secondary” and “tertiary” variants, controlled by a prop, each of which is associated with its own unique styles.
Including a specific component variant is then as simple as passing a variant prop:
Similarly to the concept of a variant, some components accept a prop called colorScheme (or more specific props like textColorScheme).
The use of this prop will result in the component applying default styles suitable for “light” or “dark” mode. Note that, for example, ProductCard makes use of CSS vars --product-card-light-background and --product-card-dark-background, selectively applying the appropriate one for the current color scheme.
Practice the use of targeted CSS variables to control the appearance of a component in a specific context.
The Button component supports the CSS variable --button-primary-background to set the background color when the “primary” variant is rendered. A global value for this var (set either in app/globals.css or via the Site Theme configuration in Makeswift) will apply to all buttons in the storefront. However, we can set it in a narrower context if required.
app/[locale]/(default)/product/[slug]/page.tsx and find <ProductDetail>.<ProductDetail> in an element with an appropriate style prop to set the button background CSS var.This is a bit of a contrived example, as you will likely want to keep a consistent look and feel for buttons throughout the theme. If you do need additional appearance options beyond the existing variants, it would be advisable to modify your Button component definition to add new variants.
The Toaster component enables simple and unobtrusive UI notifications displayed to users in response to their interactions, such as a success or error message after an “add to cart” action completes, is an important UI concern but can be cumbersome to build out from scratch.
The necessary layout config is built into Catalyst by default, and notifications can be initiated from anywhere:
As we’ve seen, Suspense boundaries can be used to render components asynchronously, allowing their content to be streamed to the browser when ready.
Catalyst enhances this capability with the component Stream (see vibes/soul/lib/streamable.tsx). Stream, which uses Suspense internally, accomplishes several design goals while supporting an excellent developer experience with data components:
In this simple example, the TopCategories component expects a “streamable” list of categories, meaning that the prop may be a Promise yet to be resolved or may be a simple array. The <Stream> component and its callback function take care of displaying a fallback if necessary until the streamable value is available, and the wrapped JSX can deal with categories in typical fashion.
This pattern keeps the concern of fallback behavior within the component while also avoiding assumptions about receiving a Promise. The data fetching is a concern outside the component.
In the context where the data fetch is set up, the recommended pattern is to use the Streamable.from callback to create a Promise that will not be executed until the component ultimately awaits it.