THIS PROJECT IS NOT ACTIVE
I played with it a bit, but did not achieve what I wanted. I'm just publishing it in case the original author of this project wants to pick up some of my changes.
UnoCSS preset for Quasar Framework v2. Replaces Quasar's Sass-based CSS with UnoCSS, exposing all ~383 Quasar variables as CSS custom properties and supporting both Material Design 2 (standard Quasar look) and Material Design 3 styles.
Based on unocss-preset-quasar, but many changes were made to the MD2 preset. The author of the original package seems to be focusing on MD3, while I am first focusing on getting MD2 as identical to Quasar as possible. In that process, I have broken a significant portion of his MD3 work. Contrary to what the paragraph above here claims, Material Design 3 is in no way operational.
In your Quasar project:
#TODO this is for the original project, update
pnpm add unocss unocss-preset-quasar @iconify-json/mdiimport UnoCSS from 'unocss/vite'
import { QuasarPreset, MaterialDesign2 } from 'unocss-preset-quasar'
export default defineConfig((ctx) => ({
build: {
extendViteConf(viteConf) {
viteConf.plugins.push(
UnoCSS({
presets: [
QuasarPreset({
style: MaterialDesign2,
})
]
})
)
}
}
}))Quasar's app-vite injects import 'quasar/dist/quasar.sass' into the entry point. Replace it with virtual:uno.css via a Vite plugin added to the same extendViteConf:
viteConf.plugins.push(
{
name: 'quasar-strip-sass',
enforce: 'pre',
transform(code, id) {
if (code.includes("import 'quasar/dist/quasar.sass'")) {
return code.replaceAll(
"import 'quasar/dist/quasar.sass'",
"import 'virtual:uno.css'"
)
}
}
},
UnoCSS({ presets: [QuasarPreset({ style: MaterialDesign2 })] })
)The preset auto-discovers src/css/quasar.variables.scss (or .sass) in your project root. Any standard Quasar Sass variable overrides in that file are picked up automatically — no extra config needed.
// src/css/quasar.variables.scss
$primary: #ff0000;
$button-border-radius: 8px;Pass overrides directly in quasar.config.js. Keys use camelCase versions of the Quasar Sass variable names (without the $ prefix):
QuasarPreset({
style: MaterialDesign2,
variables: {
primary: '#ff0000',
buttonBorderRadius: '8px',
bodyFontSize: '16px',
}
})JS overrides take highest priority in the UnoCSS resolution pipeline (component shortcuts, --q-* CSS custom properties).
At startup the preset writes a generated Sass file to .quasar/unocss-resolved-variables.scss containing all resolved variable values — including any JS overrides. Import it at the top of your variables file to make those values available in <style lang="scss"> blocks:
// src/css/quasar.variables.scss
@import '../../.quasar/unocss-resolved-variables';
// Any $variable assignments below this line override the bridge values
// in <style lang="scss"> blocks (but NOT in UnoCSS output)
$primary: #ff0000;The .quasar/ directory is already in .gitignore in standard Quasar projects (it is generated on every dev server start / build).
The bridge file contains the fully resolved values from all layers of the pipeline, including JS config overrides. When you import it at the top of your quasar.variables.scss, all those values become available as $variables in every <style lang="scss"> block in your project.
If you only use the Sass file (no JS config): Everything stays in sync automatically. The preset reads your Sass file, resolves the values, writes them to the bridge, and the Sass preprocessor uses the same file. UnoCSS output and <style lang="scss"> blocks see identical values.
If you only use JS config (no Sass file overrides below the import): The bridge file carries the JS values into <style lang="scss"> blocks if you've imported it as described above. Everything stays in sync.
If you set the same variable in both JS config AND your Sass file (below the import): They diverge. The bridge import sets the variable to the JS value, but your Sass assignment immediately overrides it. So:
- UnoCSS output uses the JS value (JS wins in the resolution pipeline)
<style lang="scss">blocks use your Sass file value (it comes after the bridge import, so it wins in Sass)
This only happens when the same variable has different values in both places. To keep things simple: override each variable in one place only.
| Approach | UnoCSS output | <style lang="scss"> |
Recommendation |
|---|---|---|---|
| Sass file only | Yes | Yes | Best for most projects |
| JS config only (with bridge import, no overrides below it) | Yes | Yes | Good for config-driven setups |
| Both with same values | Yes | Yes | Redundant but safe |
| Both with different values | JS value | Sass value | Avoid — causes mismatch |
All resolved variables are emitted as --q-* CSS custom properties on :root:
:root {
--q-primary: #1976d2;
--q-button-border-radius: 3px;
--q-body-font-size: 14px;
/* ... all ~383 variables */
}These can be read in plain CSS (var(--q-primary)), overridden at runtime via JavaScript (document.documentElement.style.setProperty('--q-primary', '#f00')), or inspected in DevTools.
Use MaterialDesign3 instead of MaterialDesign2:
import { QuasarPreset, MaterialDesign3 } from 'unocss-preset-quasar'
QuasarPreset({
style: MaterialDesign3,
sourceColor: '#806cb0', // palette seed color
})When MD3 palette generation is active, a full harmonized color scheme is derived from sourceColor. The resulting tokens are emitted alongside standard variables, prefixed with md3-:
:root {
--q-md3-primary-container: #ecdcff;
--q-md3-surface-variant: #e7e0ec;
/* ... */
}Do not override individual brand colors ($primary, $secondary, etc.) in your variables file when using MD3 palette mode — use sourceColor to control the entire palette instead.
To force palette generation on or off regardless of which style is active, use generateMd3Palette:
QuasarPreset({
style: MaterialDesign2,
sourceColor: '#806cb0',
generateMd3Palette: true, // force on even with MD2
})presetWind4 is included, so all Tailwind4 CSS compact utility classes are available - but in case of conflict, the
Quasar definition wins.
Note that Quasar padding and margin classes are translated to Tailwind, which uses rem under the hood rather than
px. The results are the same with Quasar default settings, but if you change for example the font size away from
the default 16px, this can have an effect on these classes.
Variables are resolved in the following order (later layers win):
1. Quasar built-in defaults
2. Style defaults (MD2 or MD3 can override Quasar defaults)
3. MD3 palette (if enabled, overrides brand colors)
4. User's quasar.variables.scss / .sass file
5. JS config (variables option) — highest priority
This resolution order applies to UnoCSS output (component CSS, --q-* custom properties). The resolved values are also written to the bridge file, so they flow into <style lang="scss"> blocks too — unless you override them again below the bridge import in your Sass file (see "How the bridge works" above).
| Option | Type | Default | Description |
|---|---|---|---|
style |
QuasarStyle |
required | MaterialDesign2 or MaterialDesign3 |
sourceColor |
string |
— | MD3 palette seed color (hex) |
generateMd3Palette |
boolean | null |
style default | Force MD3 palette on (true) or off (false); null/undefined defers to the style |
variables |
Partial<QuasarVariables> |
— | JS variable overrides (highest priority); flows into <style lang="scss"> via the bridge file |
variablesFile |
string | false |
auto-discover | Path to Sass variables file, or false to disable auto-discovery |
resolvedVariablesPath |
string |
.quasar/unocss-resolved-variables.scss |
Output path for the generated Sass bridge file |
plugins |
(keyof QuasarPlugins)[] |
— | Quasar plugins whose classes to include in the safelist |
iconSet |
QuasarIconSet |
— | Icon set |
presetWebFonts |
WebFontsOptions |
Roboto via Bunny Fonts | Web fonts config passed to @unocss/preset-web-fonts |
import { QuasarPreset, MaterialDesign2, MaterialDesign3 } from 'unocss-preset-quasar'
import { type QuasarStyle } from 'unocss-preset-quasar/styles'
import { type QuasarTheme } from 'unocss-preset-quasar/theme'- Base preset:
presetWind4()(Tailwind Wind v3 compatible) provides utility classes. - Shortcuts: Regex patterns that match Quasar class names (
q-btn,q-card, etc.) and expand to UnoCSS utility strings. Component files each exportshortcutsand optionallypreflightsfor raw CSS. - Preflights: Raw CSS injected for things that cannot be expressed as utilities (keyframes, complex selectors,
repeating-linear-gradient). - Safelist: Classes that UnoCSS must always generate, even when not found in scanned templates. Required for dynamically-added classes (ripple, color modifiers, transitions).
- CSS Layers:
components(-1) →default(1) →utilities(2). Root-level layout defaults uselayer-components:so utility classes always win.
git clone https://github.com/simsustech/unocss-preset-quasar.git
cd unocss-preset-quasar
pnpm i
pnpm run build
cd packages/dev # or cd packages/docs
pnpm run devMIT