Configuration
A guide to configuring and customizing your Windi JS experience.
Note: If you've ever used Windi CSS, the configuration of Windi JS is not exactly the same as that of Windi CSS v3.x. There are some differences and some are the same. Full compatibility will not be available until the release of Windi CSS v4.0.
Config File
The Windi JS configuration file named windi.config.js
or windi.config.ts
, it should place in the root directory of your project and export a configuration object. Here’s an example:
import { baseColors, bootstrapColors, colorHandler, configHandler, css, defineConfig, gradientConfig } from "windijs";
const colors = {
...baseColors,
...bootstrapColors,
};
export default defineConfig({
theme: {
// overwrite theme
colors,
fontFamily: {
sans: ["Graphik", "sans-serif"],
serif: ["Merriweather", "serif"],
},
// extend theme
extend: {
borderRadius: {
xxl: "2rem",
},
},
},
utilities: {
// overwrite utility
bg: {
DEFAULT: colorHandler(colors, "backgroundColor", "--w-bg-opacity"),
},
// create new utilities
myColor: {
red: css({
backgroundColor: "#FF2F41",
}),
},
gradient: {
DEFAULT: configHandler(gradientConfig, "backgroundImage"),
},
},
variants: {
// create new variants
hocus: "&:hover, &:focus",
},
});
Although you can also use object directly, like below.
/** @type {import("windijs").Config} */
export default {
/* configurations... */
};
Configuration Options
Theme
The theme section is where you define your color palette, fonts, type scale, border sizes, breakpoints — anything related to the visual design of your site.
export default defineConfig({
theme: {
colors: {
blue: "#1fb6ff",
purple: "#7e5bef",
pink: "#ff49db",
orange: "#ff7849",
green: "#13ce66",
yellow: "#ffc82c",
grayDark: "#273444",
gray: "#8492a6",
grayLight: "#d3dce6",
},
fontFamily: {
sans: ["Graphik", "sans-serif"],
serif: ["Merriweather", "serif"],
},
extend: {
borderRadius: {
xxl: "2rem",
},
},
},
});
Learn more about the default theme and how to customize it in the theme configuration guide.
Utilities
The utilities of Windi JS are very easy to add and customize. Let's take official border
as an example, which support [border
, border.solid
, border.dashed
, ..., border[0]
, border[2]
, ..., border.red[500]
, ..., border.opacity[10]
].
import { borderStyleConfig, borderWidthConfig, opacityConfig, colorHandler, configHandler, meld, prop } from "windijs";
import { colors } from "@windijs/utilities";
export default defineConfig({
utilities: {
border: {
DEFAULT: meld(
configHandler(borderStyleConfig, "borderStyle"),
configHandler(borderWidthConfig, "borderWidth"),
colorHandler(colors, "borderColor", "--w-border-opacity")
),
opacity: configHandler(opacityConfig, prop`--w-border-opacity`),
},
},
});
[borderStyleConfig
, borderWidthConfig
, opacityConfig
, colors
] are normal JavaScript Objects, you can define them by yourself.
[configHandler
, colorHandler
] are interfaces provided by Windi JS to ease the use of config. Of course, you can also define it directly with css
API, or mix them.
import { css, prop } from "windijs";
export default defineConfig({
utilities: {
border: {
DEFAULT: css({
borderStyle: "solid",
borderWidth: "1px",
}),
solid: css({
borderStyle: "solid",
}),
dashed: css({
borderStyle: "dashed",
}),
0: css({
borderWidth: "0px",
}),
2: css({
borderWidth: "2px",
}),
red: css({
"--w-border-opacity": "1",
borderColor: "rgba(29, 78, 216, var(--w-border-opacity))",
}),
opacity: {
0: css({
"--w-border-opacity": "0",
}),
10: css({
"--w-border-opacity": ".1",
}),
25: css({
"--w-border-opacity": ".25",
}),
},
},
},
});
Learn more about the default utilities and how to create a new utility in the utility configuration guide.
Variants
Like utilities, the variants of Windi JS are also simple to define.
import { defineConfig } from "windijs";
export default defineConfig({
variants: {
sm: "@media (min-width: 640px)",
hover: "&:hover",
dark: "@media (prefers-color-scheme: dark)",
hocus: "&:hover, &:focus",
// TODO: support array variants
smDark: ["@media (min-width: 640px)", "@media (prefers-color-scheme: dark)"],
smDarkHover: ["@media (min-width: 640px)", "@media (prefers-color-scheme: dark)", "&:hover"],
},
});
Learn more about the default variants and how to create a new variant in the variant configuration guide.
DarkMode
By default, darkMode option value is media
, which relying on the operating system preference.
export default defineConfig({
darkMode: "media",
});
Generated css example:
@media (perfer-color-scheme: dark) {
.dark\:leading-none {
line-height: 1;
}
.dark\:leading-tight {
line-height: 1.25;
}
}
If you want to support toggling dark mode manually, you can use the class
strategy instead of the media
strategy:
export default defineConfig({
darkMode: "class",
});
Generated css example:
.dark .leading-none {
line-height: 1;
}
.dark .leading-tight {
line-height: 1.25;
}
Customizing the class name
Some frameworks (like NativeScript) have their own approach to enabling dark mode and add a different class name when dark mode is active.
You can overwrite the dark mode variant in variants options.
export default defineConfig({
darkMode: false, // whatever
variants: {
dark: '[data-mode="dark"] &', // customize variants will overwrite the darkMode option
},
});
Important
The important
option lets you control whether Windi’s utilities should marked with !important
. This can be useful when using Windi JS with existing CSS that has high specificity selectors.
WARNING
The important
config is not supported yet.
To generate utilities as !important
, set the important
key in your configuration options to true
:
export default defineConfig({
important: true,
});
Now all Windi’s utility classes will generated as !important:
.leading-none {
line-height: 1 !important;
}
.leading-tight {
line-height: 1.25 !important;
}
Selector strategy
Setting important
to true can introduce some issues when incorporating third-party JS libraries that add inline styles to your elements. In those cases, Windi’s !important
utilities defeat the inline styles, which can break your intended design.
To get around this, you can set important
to an ID selector like #app
instead:
export default defineConfig({
important: "#app",
});
This configuration will prefix all your utilities with the given selector, effectively increasing their specificity without actually making them !important
.
#app.leading-none {
line-height: 1;
}
#app.leading-tight {
line-height: 1.25;
}