Theming


Core Concepts

In this section, we will talk about Vactory Next core concepts such as fonts, PostCSS, Dark mode, RTL, Icons, etc.

Fonts

⚠️
Don't use SELF HOSTED fonts. Self-hosted fonts require a license, which developers might forget to obtain, potentially causing legal issues. You can only use fonts from Google Fonts & Monotype

You can configure your custom fonts either by using next/font/google in your _app.jsx file:

_app.jsx

import { Inter, Cairo } from "next/font/google"
const inter = Inter({
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
display: "swap",
subsets: ["latin"],
})
export default function App({ Component, pageProps }) {
return (
<>
<style jsx global>{`
:root {
--sans-font-family: ${inter.style.fontFamily};
}
`}</style>
// ...
// ...
// Rest of code
<>
)
}

Or by using the <link> HTML tag in your _document.jsx file's Head:

_document.jsx

<Head>
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap"
rel="stylesheet"
/>
</Head>

PostCSS

When using Tailwind CSS with Next.js, PostCSS plays a crucial role. Next.js has built-in support for PostCSS, allowing you to easily configure and apply transformations to your CSS. By setting up PostCSS in Next.js, you can leverage plugins such as Autoprefixer (to add vendor prefixes).

This an example of our postcss.config.js file:

postcss.config.js

module.exports = {
plugins: [
// The 'tailwindcss/nesting' plugin enables the use of nested CSS selectors, similar to Sass or Less syntax.
"tailwindcss/nesting",
// The 'tailwindcss' plugin is the core plugin for integrating Tailwind CSS
"tailwindcss",
// The postcss-rtlcss plugin is used for transforming CSS from left-to-right (LTR) to right-to-left (RTL) direction.
// The configuration object { mode: "combined", useCalc: true } specifies the mode of transformation as "combined" and enables the use of calc function in the RTL styles.
["postcss-rtlcss", { mode: "combined", useCalc: true }],
// The autoprefixer plugin automatically adds vendor prefixes to CSS properties, ensuring cross-browser compatibility.
"autoprefixer",
],
}

Dark Mode

Tailwind includes a dark variant that lets you style your site differently when dark mode is enabled. For example, you can display a blue background-color when the device theme is set to light, and a red background when the device's theme is set to dark as shown below.

<div class="bg-blue dark:bg-red">
<h1>Dark mode</h1>
</div>

By default this uses the prefers-color-scheme CSS media feature, but you can also build sites that support toggling dark mode manually using the ‘class’ strategy.

RTL/LTR Support

Use the rtl and ltr modifiers to conditionally add styles in right-to-left and left-to-right modes respectively when building multi-directional layouts.

We have already configured RTL with PostCSS, which automatically switches classes that contain "left," "right," "top," or "bottom" to their opposites. For example, right-2 becomes left-2

Icons

To add a new icon to your project, follow these steps:

  • Place the icon in the YOUR_WORKSPACE/icons folder
  • Run the command yarn workspace YOUR_WORKSPACE icons:build
  • This process will add the icon to the YOUR_WORKSPACE/public/icons.svg file
  • You can access the icon by using the SVG ID, which corresponds to the name you assigned to your icon file:
import { Icon } from "@/ui"
// if your SVG file is called 'arrow-left.svg', the you can use it this way:
;<Icon id="arrow-left" width="16px" height="16px" />

Components folder

In this section, we will focus on the components folder, which contains the following structure: elements, modules, and widgets.

The folder structure is organized as follows:

  • elements: Basic UI building blocks
  • modules: Module components organized by type
    • modules/contrib: Core module components provided by Vactory
    • modules/custom: Project-specific custom module components
  • widgets: Widget components organized by type
    • widgets/contrib: Core widget components provided by Vactory
    • widgets/custom: Project-specific custom widget components

Most of the theming occurs in the files inside these folders. Let's examine each one of them, understand their purpose, and learn how to theme them:

I. Elements:

This folder contains reusable UI components that represent basic building blocks of your design. These components are typically styled at a low level and can be composed together to create more complex components.

For a better understanding, let's not just explain an existing element; instead, we will create a new element together and theme it. This hands-on approach will provide a practical experience in creating and customizing a component.

  1. Create a new component: Inside the elements folder, let's create a new file called Button.jsx. This file will contain the code for our custom button component.

  2. Define the component: In Button.jsx, define a functional React component for our button ( Don't use class components because it's deprecated )

button/Button.jsx

export const Button = ({ children }) => {
return (
<div>
<button>{children}</button>
</div>
)
}
  1. Style the component: Now, let's style our custom button. Usually, you might do this by creating a custom CSS file or using Tailwind classes directly inside your component. However, in our case, we are going to use a different approach which allows us to create multiple variants for a single component. Let's dive deeper into this:
  • Create a theme.js file: Inside the button folder, create a new file called theme.js. This file will hold our custom button styles and variants.

  • Define button variants: In theme.js, define different variants for our custom button. For example, let's create a primary variant:

button/theme.js

export const buttonVariants = {
primary: {
wrapper: "flex items-center",
element: "bg-primary-500 p-4 text-white",
},
secondary: {
wrapper: "flex items-center",
element: "bg-secondary-500 p-2 text-black",
},
}
  • Update the component: Now, update the Button.jsx component to utilize the variant styles defined in theme.js. Modify the component code as follows:

button/Button.jsx

import { buttonVariants } from "./theme"
export const Button = ({ variant = "primary", children }) => {
return (
<div className={buttonVariants[variant].wrapper}>
<button className={buttonVariants[variant].element}>{children}</button>
</div>
)
}

In the updated component, we added a variant prop that allows you to specify the desired button variant. By default, it is set to primary.

Now the structure of your folder will look like somthing like this:

apps
|------ YOUR_WORKSPACE
|------|------ components
|------|------|------ elements
|------|------|------|------ button
|------|------|------|------|------ Button.jsx
|------|------|------|------|------ theme.js
  1. Exporting the Element: Now you have to export your Button element and make it avalaible using Path Aliases, simply just add the following line of code to components/elements/index.js :
export { Button } from "./button/Button"

This line exports the Button component from the Button file, allowing you to import and use it using path aliases.

  1. Using the component: You can now use the Button component with different variants in your application. For example:
import React from "react"
import Button from "@/ui"
const App = () => {
return (
<>
<h1>Welcome to Vactory Next</h1>
<Button variant="primary">Primary Button</Button>
<Button variant="secondary">Secondary Button</Button>
</>
)
}
export default App

II. Widgets:

The widgets folder contains widget components organized by type:

Contrib Widgets (./components/widgets/contrib): These are core reusable UI components provided by Vactory that offer specific functionality with different variants. Examples include different Header variants, Slider variants, Banner components, Anchor components, and other interface elements. These components are designed to be reused across projects and can be customized through theming to match your design requirements.

Custom Widgets (./components/widgets/custom): These are project-specific widget components that you create or customize for your particular project needs. They follow the same patterns as contrib widgets but are tailored to your specific requirements.

Check this section to learn more about Widgets: Static templates

III. Modules:

The modules folder contains module components organized by type:

Contrib Modules (./components/modules/contrib): These are core complex components provided by Vactory that handle complete content types and advanced functionality. Examples include News modules, Blog modules, Forum modules, Webform modules, and other content management features. These modules are more complex compared to widgets as they handle data processing, content rendering, and user interactions for specific content types.

Custom Modules (./components/modules/custom): These are project-specific module components that provide functionality unique to your project. They can extend or completely replace contrib modules when you need specialized behavior.

Check this section to learn more about Modules: Dynamic templates