WovenUI vs Bulma
The utility-first framework for Sass teams who want components that look like their own product. WovenUI gives you classes with readable names, the same utilities as apply() mixins for any custom value, and semantic theme tokens that cover light, dark, inverse and high contrast from one markup. Like Bulma it ships no JavaScript, and mistakes stop the build with the fix in the message.
Side by side
| Topic | WovenUI | Bulma |
|---|---|---|
| Custom values | Any value, right in your component CSS: apply(p(13px), bg(#bada55)), with the same states and breakpoints as the utilities and checked by the compiler. A unitless number is a scale key; a value with a unit is used as written. | Change the Sass variables the helpers and components read, or override a CSS variable at a narrower scope [4][8][10]. |
| Catching mistakes | Mistakes stop the build with the fix in the message. An unknown key, color, token or modifier in a mixin, the configuration or token() fails the compile and lists the valid options: apply(p(7)) gives p: 7 is not a configured key. Valid keys: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32, 40, 48, 56, 64. Write a unit for a custom value (7px, 7rem). | Not documented. |
| Dark mode and themes | Light, dark, inverse and high contrast from one markup. Semantic tokens switch with data-theme="light", "dark" or "inverse" on any element; without data-theme the operating system decides. data-contrast="high" applies your $high-contrast-light and $high-contrast-dark maps. A new theme token goes into $light-theme and $dark-theme and gets classes and mixin support. | A theme is a collection of CSS variables. Light is required, dark is optional, and each is scoped by @media (prefers-color-scheme), [data-theme=dark] and .theme-dark, on any element or on <html> [5][6]. A custom theme is your own variables under a name and a scope [6]. |
| Components | Components that look like your product. Free, step-by-step recipes for a card, navbar, form field, dark mode toggle, dashboard layout and pricing table. Plain HTML buttons and form fields are styled from tokens, tooltips are included, and any component library you already use works alongside. | "Modern CSS framework based on Flexbox" [1], with ready-made elements and components such as buttons, cards, navbars and modals, styled with modifier classes [9][12][13]. |
| Class names | Names you can read: between, x-center, bg-surface, z-modal, with the breakpoint as a suffix: p-6@lg. In SCSS every modifier follows the utility: apply(p(6) lg, bg(brand-hover) hover). Spacing such as px, mx and ms is logical, so layouts follow right-to-left text. | Component classes plus modifiers: button is-primary is-large, card, card-content [12][13]. The breakpoint sits at the end of a helper name: is-flex-tablet-only, is-hidden-fullhd [16], and column sizes such as is-half-desktop [17]. |
| Utilities | One vocabulary for HTML and SCSS: every utility class is generated from a configuration map, and every utility is also a mixin for apply(). Change a map and the classes and mixins follow. | Helper classes for spacing (m* and p* in all directions, sizes 0 to 6), flexbox, visibility, color and typography [14][15][16]. The spacing page counts 112 spacing helpers, reduced to 18 by customizing the Sass variables [14]. |
| Design tokens | Semantic roles out of the box: --wu-* custom properties for surfaces, text, borders, focus, brand and status roles, plus the palette and every scale. Classes and mixins output var(--wu-*), and token(name) raises an error for an unknown name, so a typo never reaches the browser. | Every variable is prefixed bulma- and defined on :root or on a component such as .button; a variable set at a more specific scope overrides the global one [4]. Bulma can be customized with CSS variables alone [3][11]. |
| Color and contrast | Readable text on every fill: text-on-brand and every other text-on-{role} token are picked for contrast at compile time, with a warning below 4.5:1. Shades 50, 100 to 900 and 950 for every role and hue are generated in OKLCH from your color, and theme tokens such as bg-surface and text-muted flip per theme. | For each of text, link, primary, info, success, warning and danger, Bulma generates CSS variables from hue, saturation and lightness (for example --bulma-primary-h), with 21 shades from 00 to 100 and an invert color for each [7]. |
| Configuration | One @use ... with (...) block: $brand, scale maps, theme override maps and feature flags. Everything is validated at compile time, and a wrong key raises an error that names it. | Five levels: global Sass variables, component Sass variables, global CSS variables, component CSS variables and helper classes. Initial variables hold literal values; derived variables are calculated from them [10]. |
| Component styles | Made for component stylesheets. @wovenui/core/mixins has the full API and outputs no CSS: configure once in a partial, and each CSS module or Vue, Svelte or Astro <style lang="scss"> block compiles to its own rules only. | Built with Dart Sass; the docs recommend the sass npm package [3][8]. Override variables with @use "bulma/sass" with (...) [8], or load only the modules you need, such as bulma/sass/elements/button, and configure each with with [9]. |
| CSS you ship | Only what you use. By default you ship only the rules you write: tokens and base styles are 5.8 KB gzipped, and each component adds only its own rules, with no purge step. Feature flags switch whole groups off. Using the prebuilt file with every class? See Ship only the classes you use. | Ships bulma.css and a minified file, plus prebuilt variants without dark mode, without helpers and with prefixed classes [2]. With Sass you can load only the modules you use [9]. |
| Setup | Link the prebuilt dist/wovenui.min.css with no build step, or @use "@wovenui/core" with Dart Sass 1.79 or later (below 2.0) for apply() and your own configuration. No framework plugin, no PostCSS plugin. Setup guides for React, Next.js, Vue, Svelte, Astro and plain HTML, plus a playground to try it in the browser. | Install the compiled file from npm or load it from a CDN [1]. Customizing through Sass needs Dart Sass [8]. |
| JavaScript | None. No runtime, and tooltips are CSS only. Your own scripts or any library add interactive behavior. | None. The sole output is a CSS file and the README states that no JavaScript is included [1]. |
| Editor support | The WovenUI extension for VS Code: completion, hover docs, color swatches and one-click fixes for apply(), classes and tokens. | Not documented. |
| AI assistants | A complete guide ships in the package at docs/llms-full.txt and on this site at /llms-full.txt, with a short index at /llms.txt, so an assistant writes valid WovenUI code. | Not documented. |
| License | MIT. | MIT. |
The same component in both
One card, written both ways. Bulma provides its card and button classes; WovenUI builds the same card from theme token classes (bg-surface, text-muted, border), or as your own BEM classes with apply(), so every value follows your brand and the theme: it is rendered below in a light and a dark section. Then Sass configuration and theme scoping side by side.
<div class="flex col gap-3 p-6 bg-surface border rounded-lg hover:shadow-md">
<h3 class="text-lg font-semibold">Card title</h3>
<p class="text-muted">Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<a href="#" class="self-start px-4 py-2 rounded-md bg-brand text-on-brand">Go somewhere</a>
</div><div class="card">
<header class="card-header">
<p class="card-header-title">Component</p>
</header>
<div class="card-content">
<div class="content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</div>
</div>
<footer class="card-footer">
<a href="#" class="card-footer-item">Save</a>
<a href="#" class="card-footer-item">Edit</a>
<a href="#" class="card-footer-item">Delete</a>
</footer>
</div>
<button class="button is-primary is-large">Go somewhere</button>@use "@wovenui/core" as * with (
$brand: #8a4d76,
$light-theme: ("bg-card": gray 50),
$dark-theme: ("bg-card": #202020)
);
.card {
@include apply(
flex, col, gap(3), p(6),
bg(card), rounded(lg), border(1),
shadow(md) hover
);
max-width: 18rem;
}
.card__title {
@include apply(font-size(lg), font(semibold));
}
.card__text {
@include apply(text-color(muted));
}
.card__action {
@include apply(
self-start, px(4), py(2), rounded(md),
bg(brand), text-color(on-brand), bg(brand-hover) hover
);
}$purple: #8a4d76;
$pink: #fa7c91;
// Path to Bulma's sass folder
@use "bulma/sass" with (
$family-primary: '"Nunito", sans-serif',
$primary: $purple,
$link: $pink,
$control-border-width: 2px,
$input-shadow: none
);<html data-theme="dark">
<body class="bg-base text-regular">
<aside data-theme="light" class="bg-surface p-4">
A light section on a dark page
</aside>
</body>
</html><html data-theme="dark">
<body>
<div data-theme="light">
A light section on a dark page
</div>
</body>
</html>Moving from Bulma
- Start from the free recipes, such as the card and the navbar, and build each component as your own class with
apply()or as utility markup. See apply(). - Replace modifier classes with tokens and mixins:
is-primarybecomesbg(brand)withtext-color(on-brand), and size modifiers become values such aspx(4)andfont-size(lg). See Spacing. - Move the breakpoint into the suffix or the modifier: a helper such as
is-flex-tabletbecomesflex@mdas a class, orflex mdinsideapply(). See Media queries. - Replace the
@use "bulma/sass" with (...)block with one@use "@wovenui/core" with (...)block. See Configuration. - Replace
--bulma-*variables and[data-theme=...]blocks with--wu-*tokens and the$light-themeand$dark-thememaps. See Theming and Tokens. - Keep your scripts: both are CSS-only, so interactive parts you wrote on top of Bulma carry over unchanged. Core tooltips are CSS only: see Tooltips.
- Install the WovenUI extension for VS Code for completion and hover docs while you convert, and look up any mixin or function in the A to Z reference.
Sources
Every statement about Bulma on this page comes from its official documentation or repository. Statements about WovenUI come from the core source, its changelog and the core documentation.
- [1] Bulma repository: README
- [2] Bulma repository: package.json
- [3] Bulma 1.0.0 release notes
- [4] Bulma docs source: CSS variables
- [5] Bulma docs source: Dark mode
- [6] Bulma docs source: Themes
- [7] Bulma docs source: Color palettes
- [8] Bulma docs source: Customize with Sass
- [9] Bulma docs source: Customize with modular Sass
- [10] Bulma docs source: Customization concepts
- [11] Bulma docs source: Customize with CSS variables
- [12] Bulma docs source: Button
- [13] Bulma docs source: Card
- [14] Bulma docs source: Spacing helpers
- [15] Bulma docs source: Flexbox helpers
- [16] Bulma docs source: Visibility helpers
- [17] Bulma docs source: Columns responsiveness