@marwes-ui/presets
v1.3.0
Published
Static preset CSS and theme exports for Marwes React, Vue, and custom adapter projects.
Downloads
1,363
Readme
Static preset CSS and theme exports for Marwes React, Vue, and custom adapter projects.
Marwes Design System - Presets
Static default CSS and preset theme exports for Marwes React and Vue apps.
Static .mw-* CSS • CSS variables • Default Marwes visuals • No runtime CSS-in-JS
Documentation • React Storybook • Vue Storybook • GitHub
Why Use It
Most apps install @marwes-ui/react or @marwes-ui/vue, and those adapters load the default preset automatically. Install presets directly when you need the standalone CSS path, the explicit firstEditionTheme object, or preset CSS in a custom adapter.
Presets gives Marwes its default visual layer:
- default component CSS
- theme-variable driven colors, radius, focus, typography, density, and state styling
- stable
.mw-*class styling for every shipped component family - no CSS-in-JS runtime
- CSS that follows the same core recipes used by React and Vue
Package Map
Presets are the static visual layer, not the normal app entry point.
| Package | Use it when |
| --- | --- |
| @marwes-ui/react | You are building a React app. |
| @marwes-ui/vue | You are building a Vue app. |
| @marwes-ui/core | You need framework-agnostic recipes, theme utilities, accessibility contracts, or adapter/tooling APIs. |
| @marwes-ui/presets | You need standalone preset CSS or preset theme exports. |
This package gives humans and AI agents a predictable CSS contract: .mw-* classes consume --mw-* variables generated by the provider, while adapters stay thin.
Install
pnpm add @marwes-ui/presetsNormal App Setup
React and Vue apps normally import only the adapter:
import { Button, ButtonVariant, MarwesProvider } from "@marwes-ui/react"
export function App() {
return (
<MarwesProvider>
<Button variant={ButtonVariant.primary}>Save</Button>
</MarwesProvider>
)
}Direct CSS Import
Use the direct CSS path for custom adapters, static prototypes, or tooling that needs the preset without the React/Vue entry.
import "@marwes-ui/presets/firstEdition/styles.css"Available Styled Families
The default preset styles these Marwes families today:
- Accordion and accordion fields
- Avatar and avatar groups
- Badge and contextual badge variants
- Button and purpose button variants
- Card variants
- Checkbox, checkbox fields, and checkbox groups
- Dialog and dialog modal
- Divider
- Icon
- Input, textarea, select, rich text, OTP, and field variants
- Paragraph and heading typography
- Radio and radio groups
- Slider and slider fields
- Spacing and spacer primitives
- Spinner variants
- Switch and switch fields
- Tab groups and panels
- Toast and toast container
- Tooltip and tooltip groups
Custom Theme With Preset CSS
Preset CSS consumes provider-generated --mw-* variables. Marwes is designed to look great from the beginning: map an existing design library or graphical profile into a partial ThemeInput, override only the tokens your product owns, pass it to MarwesProvider, and the preset follows it.
import { MarwesProvider, mwAvailableFonts, type ThemeInput } from "@marwes-ui/react"
const brandTheme = {
color: {
primary: "#2457FF",
danger: "#D90429",
success: "#15803D",
warning: "#D97706",
background: "#F8FAFC",
surface: "#FFFFFF",
surfaceElevated: "#FFFFFF",
text: "#111827",
textMuted: "#4B5563",
border: "#D1D5DB",
focus: "#2457FF",
},
font: {
primary: mwAvailableFonts.Poppins,
secondary: mwAvailableFonts.Lora,
},
ui: {
radius: 10,
density: "comfortable",
},
} satisfies ThemeInput
<MarwesProvider theme={brandTheme}>
<App />
</MarwesProvider>Light And Dark Mode
The preset CSS already contains the light and dark visual rules. In React and Vue apps, use ThemeMode.light and ThemeMode.dark instead of string literals, then let MarwesProvider own the active mode and toggle it with the adapter hook:
import { Button, ButtonVariant, MarwesProvider, ThemeMode, useThemeMode } from "@marwes-ui/react"
function ThemeToggle() {
const { mode, toggleMode } = useThemeMode()
return (
<Button variant={ButtonVariant.secondary} onClick={toggleMode}>
Use {mode === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark} mode
</Button>
)
}
export function App() {
return (
<MarwesProvider defaultMode={ThemeMode.light}>
<ThemeToggle />
<AppShell />
</MarwesProvider>
)
}When the mode changes, the provider updates the preset's --mw-* variables and root class. Preset selectors such as .mw-theme--dark .mw-btn then pick up the correct dark-mode component states without any extra CSS in the app.
You do not need a themeByMode map for the normal toggle. With no theme prop, Marwes uses its default light and dark palettes. With shared brand overrides, pass the same partial theme object and the provider still swaps every omitted token by mode.
Use a themeByMode map only when your product wants different brand overrides in light and dark mode, such as a different primary color or surface color per mode:
import { useState } from "react"
import {
Button,
ButtonVariant,
MarwesProvider,
ThemeMode,
type ThemeInput,
useThemeMode,
} from "@marwes-ui/react"
const themeByMode = {
[ThemeMode.light]: { color: { primary: "#2457FF", background: "#F8FAFC", text: "#111827" } },
[ThemeMode.dark]: { color: { primary: "#8BA2FF", background: "#0B1020", text: "#F8FAFC" } },
} satisfies Record<ThemeMode, ThemeInput>
function ThemeToggle() {
const { mode, toggleMode } = useThemeMode()
return (
<Button variant={ButtonVariant.secondary} onClick={toggleMode}>
Use {mode === ThemeMode.dark ? ThemeMode.light : ThemeMode.dark} mode
</Button>
)
}
export function App() {
const [mode, setMode] = useState<ThemeMode>(ThemeMode.light)
return (
<MarwesProvider mode={mode} theme={themeByMode[mode]} onModeChange={setMode}>
<ThemeToggle />
<AppShell />
</MarwesProvider>
)
}firstEditionTheme
firstEditionTheme remains exported for explicit or advanced use. React and Vue providers already use the same baseline by default, so normal app code does not need to pass it.
import { firstEditionTheme } from "@marwes-ui/presets"CSS Contract
Core recipes emit:
- stable classes such as
.mw-btn,.mw-input,.mw-checkbox,.mw-card - component-scoped vars where needed
- semantic theme variables such as
--mw-color-primary-base,--mw-color-text, and--mw-ui-radius - fixed spacing variables such as
--mw-spacing-sp-24
Preset CSS must style those classes and variables consistently without adapter-specific hacks.
Plain CSS can use those variables anywhere under MarwesProvider:
.project-panel {
padding: var(--mw-spacing-sp-24);
color: var(--mw-color-text);
background: var(--mw-color-surface);
border: 1px solid var(--mw-color-border);
border-radius: var(--mw-ui-radius);
}JavaScript styling layers should import token helpers from @marwes-ui/core, @marwes-ui/react, or @marwes-ui/vue instead of duplicating var(...) strings.
Use the helper that matches the job:
mwThemeVarsreturns CSSvar(...)references for app-owned CSS-in-JS, style objects, vanilla-extract, and config files.mwThemeVarNamesreturns raw custom property names for assigning overrides or inspecting the preset CSS contract.mwVar()wraps custom or advanced--mw-*names with optional fallback support.mwStyledThememirrorsmwThemeVarsas a plain theme object for styled-components and Emotion integrations.
import { mwThemeVarNames, mwThemeVars, mwVar } from "@marwes-ui/core"
const panelStyle = {
padding: mwThemeVars.spacing.sp24,
color: mwThemeVars.color.text,
outlineColor: mwVar("--mw-color-focus", "#2457FF"),
}
const localOverride = {
[mwThemeVarNames.color.focus]: "#FF00AA",
}These helpers exist so preset CSS, adapter components, and custom application styles all follow the same provider-generated variables. That enables custom layouts and third-party styling systems to stay visually aligned with the default preset without depending on React, Vue, styled-components, or Emotion.
Accessible Styling Contract
Presets make the semantic contract visible without replacing it. Core and the adapters own roles, labels, state, and ARIA wiring; preset CSS owns the visual states that users need to perceive.
That means the default CSS includes styling for:
- visible focus states on interactive controls
- disabled, invalid, selected, expanded, checked, and busy states
- theme-driven text and background colors with contrast-aware defaults
- component classes that match the same recipes used by React and Vue
Example: an invalid input field is accessible because the adapter applies aria-invalid and aria-describedby; the preset then makes that same invalid state visually obvious through .mw-input-field--invalid and related input classes.
Package Boundaries
@marwes-ui/coreowns recipes, semantic metadata, and theme resolution.@marwes-ui/presetsowns static default CSS.@marwes-ui/reactand@marwes-ui/vueload this preset by default and render components.
Scripts
pnpm --filter @marwes-ui/presets build
pnpm --filter @marwes-ui/presets typecheck
pnpm --filter @marwes-ui/presets test