Global Styles
globalStyle() and preflight() — inject unscoped CSS once, at module level. Ideal for resets, @font-face, and base element rules.
globalStyle()
globalStyle() injects unscoped CSS into <head> exactly once. It receives a factory function that is passed css — the same builder function as this.css() in a Stylesheet class — and returns a CSSBuilder or a raw CSS string.
Use .on(selector, props) to target specific elements with the fluent builder:
import { globalStyle } from '@praxisjs/css'
globalStyle(css =>
css({})
.on('*, *::before, *::after', { boxSizing: 'border-box', margin: 0, padding: 0 })
.on('body', { fontFamily: 'system-ui, sans-serif', lineHeight: 1.5 })
.on('img, svg', { display: 'block', maxWidth: '100%' })
)Pass a raw CSS string when you need selectors or at-rules that the builder can't express:
globalStyle(_css => `
@font-face {
font-family: 'Inter';
src: url('/fonts/inter-var.woff2') format('woff2');
font-weight: 100 900;
font-display: swap;
}
`)
globalStyle(_css => `@layer reset, tokens, base, components, utilities;`)Usage pattern
Call globalStyle() at module level in a dedicated file, then import it in your app entry:
// src/base-styles.ts
import { globalStyle } from '@praxisjs/css'
globalStyle(css =>
css({})
.on('*, *::before, *::after', { boxSizing: 'border-box', margin: 0, padding: 0 })
.on('body', { fontFamily: 'system-ui', lineHeight: 1.5, color: 'var(--color-text)' })
.on('button', { font: 'inherit', cursor: 'pointer', border: 'none', background: 'none' })
.on('a', { color: 'inherit', textDecoration: 'none' })
)// src/main.ts
import './base-styles' // side-effect import — runs globalStyle() once
import { App } from './app'Deduplication
globalStyle() is content-hashed — calling a factory that produces the same CSS twice injects only one <style> element. Safe to call in modules that are imported from multiple places.
Static extraction
With the praxisjsCSS() Vite plugin, globalStyle() calls are extracted at build time. The CSS lives in the static bundle — no <style> element is injected at runtime in production.
Global styles appear before scoped class rules in the extracted CSS. This ensures resets apply before any component styles.
SSR
When document is not available (server-side rendering), globalStyle() is a no-op and does not throw. Inject global styles on the server via your framework's head management.
API
type GlobalStyleFactory = (css: (props: CSSProperties) => CSSBuilder) => CSSBuilder | string
function globalStyle(factory: GlobalStyleFactory): void| Parameter | Type | Description |
|---|---|---|
factory | GlobalStyleFactory | Receives css (= createCSSBuilder) and returns a CSSBuilder or raw CSS string. |
For component-scoped styles, use @Styled(). For scoped @keyframes animations, use keyframes().
preflight()
preflight() injects an opinionated browser reset into <head> exactly once. It normalises browser defaults across elements — removes margins and padding, resets borders, makes replaced elements block-level, and sets sensible form and typography defaults.
import { preflight } from '@praxisjs/css'
preflight()Inspired by the Tailwind CSS preflight reset, adapted to use standard system font stacks without any Tailwind-specific references.
What it resets
box-sizing: border-boxon all elements — removes margin and padding- Resets default
borderto0 solid - Sets
line-height: 1.5, system font stack (ui-sans-serif, system-ui, sans-serif, …), and disables iOS font size adjustment onhtml/:host - Removes heading font sizes and weights (
h1–h6inherit from parent) - Resets link colours and text decoration
- Makes
img,svg,video,canvas,audio,iframe,embed,objectdisplay: block; vertical-align: middle - Constrains images and videos to their parent width (
max-width: 100%; height: auto) - Removes default list styles (
ol,ul,menu) - Resets form element styles to
inherit(font,color,letter-spacing,border-radius,background-color,opacity) - Normalises
::placeholderopacity in Firefox; sets semi-transparent placeholder colour in modern browsers - Removes default textarea horizontal resize
Usage
Call preflight() at the top of your app entry before mounting the root component:
// src/main.ts
import { preflight } from '@praxisjs/css'
import { App } from './app'
preflight()
mount(App, document.getElementById('app')!)Like globalStyle(), preflight() is idempotent — calling it multiple times injects the CSS only once.
Coexisting with Tailwind (or other layered CSS)
preflight() wraps its reset in @layer reset by default. This lets it be ordered against other layered CSS — like Tailwind utilities, which live in @layer utilities — instead of always winning the cascade regardless of specificity.
Cascade layer priority follows the order layers first appear in the document: whichever layer is declared first ranks lowest. So if you combine PraxisJS with Tailwind (for example a Storybook instance documenting both design systems side by side), just make sure preflight() runs before Tailwind's CSS is evaluated — no manual layer-order declaration needed. Since static imports evaluate in source order, put the reset in its own module and import it first:
// src/reset.ts
import { preflight } from '@praxisjs/css'
preflight()// src/main.ts
import './reset' // evaluates first — registers `reset` as the lowest layer
import './tailwind.css' // Tailwind's own @layer declaration runs after, ranking higherPass a string to layer to rename it, or layer: false to opt back into un-layered CSS:
preflight({ layer: 'my-reset' })
preflight({ layer: false })Wrapping the reset in a layer only fixes cascade order — it does not deduplicate rules. If Tailwind's own preflight is also loaded, you'll get two resets running; disable one of them (e.g. Tailwind's preflight corePlugin) to avoid conflicting resets.
With the Vite plugin
preflight() is extracted at build time by praxisjsCSS() just like any other globalStyle() call. The reset CSS appears at the top of the static bundle, before all scoped component styles.
API
interface PreflightOptions {
layer?: string | false
}
function preflight(options?: PreflightOptions): void| Parameter | Type | Description |
|---|---|---|
options.layer | string | false | Names the CSS @layer the reset is wrapped in. Defaults to "reset". Pass false to inject un-layered CSS instead. |