PraxisJS

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
ParameterTypeDescription
factoryGlobalStyleFactoryReceives 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-box on all elements — removes margin and padding
  • Resets default border to 0 solid
  • Sets line-height: 1.5, system font stack (ui-sans-serif, system-ui, sans-serif, …), and disables iOS font size adjustment on html/:host
  • Removes heading font sizes and weights (h1h6 inherit from parent)
  • Resets link colours and text decoration
  • Makes img, svg, video, canvas, audio, iframe, embed, object display: 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 ::placeholder opacity 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.


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

function preflight(): void

On this page