Navigation
Page Navigation Windstorm Installation CDN Link (global variable) CDN Link (module) Node Modules Usage Macros and Markers ws-x Attribute @app and ws-screen API x(object)
Site Navigation

Windstorm

Windstorm is a library that allows element customization without needing to use css directly and without predefining hundreds or thousands of css classes with minor differences between a set of 20.

Documentation Site

Installation

Note: the version number is not necessary in the url, but is recommended. Including the version ensures that if updates are made to the library, any compatibility issues or bugs that get introduced won't affect existing pages, and also allows updates to be done when intended.

<script src="https://esm.sh/@axel669/[email protected]/dist/browser.js?raw"></script>
// Only scanning, no functions
import "https://esm.sh/@axel669/[email protected]"
// Import functions + scanning
import ws from "https://esm.sh/@axel669/[email protected]"

ws.x({...stuff})

Node Modules

npm add @axel669/windstorm

Usage

Windstorm can be used as a standalone script added to the page, or included in a bundle with other scripts/frameworks. Regardless of which form it's used in, windstorm should be included in the body of the page before the content that it will style in order to prevent FOUC. For static content, this means the script tag that uses it should not be async or defered. For content generated by a framework like React or Svelte, this should not be an issue as including windstorm in the build bundle will allow it to run before the framework adds DOM elements to the page.

Once added to the page, windstorm will scan all current elements, and any elements added later for the ws-x attribute, and generate the necessary css immediately. Component css is automatically added to the head as well, so no extra work is needed to use any of the components. Components that transform standard tags will only work if the tag has the ws-x on it (although the value can be empty).

Many of the windstorm components expect some css variables defined by the theme to be present, so a theme should always be applied to the body.

<body ws-x="@@theme:tron">
    <script src="https://esm.sh/@axel669/[email protected]/dist/browser.js?raw"></script>
    Static content here
</body>

Any html elements that do not have the ws-x attribute are left alone, allowing windstorm to play nice with any other css lib (that I tried).

Macros and Markers

Information about how macros work and how to create them is on the Macros and Markers page.

ws-x Attribute

The ws-x attribute is what windstorm will scan to apply styles to elements. The attribute can have any number of macros and markers defined.

  • Macro format: [(<size>|)?<name>(:<states>)? (arg string)?]
  • Marker format: @@<marker>(:arg)?

Macros will apply specific styles and variables to whatever element they are defined on and are used to customize individual elements in specific ways. Custom macros can be defined, and are covered in the Macros and Markers documentation.

The states for a macro are css states for controlling conditionally applied styles (ex: :hover). The size modifier for a macro will make it apply styles when certain screen size/orientation conditions are met.

Size Screen State
sm width <= 600px
md width <= 1024px
lg width >= 1025px
lnd orientation: landscape
prt orientation: portrait

Markers are bits of css that change how an element is presented in a large way (themes, making links appear as buttons, etc). Markers don't get processed by the macro system, so they can be made using standard css syntax.

<div ws-x="[@color teal] [w 100px]">
    content
    <!-- Regular border will use the --primary variable for color -->
    <!-- border-color is changed on hover only to use the --color variable -->
    <div ws-x="[b 1px solid @primary] [b.c:hover @color]">
        other content
    </div>
</div>

@app and ws-screen

The ws-screen component is designed to be a top level container for content that has consistent scrolling behavior for child elements across browsers and devices without the page resizing in weird ways from the various browser bars hiding and unhiding themselves from scrolling on mobile.

As such, the use of ws-screen is entirely optional as all components will work without it being used, and if the regular browser scrolling behavior is not an issue, then ws-screen can be skipped entirely.

If ws-screen is used, the body tag must have the @app marker added to the ws-x attribute. This will setup the css properties needed for ws-screen to control the scrolling behavior more effectively.

<!-- Using ws-screen -->
<body ws-x="@@theme:tron @@app">
    <script src="<windstorm>"></script>
    <ws-screen>
        <ws-paper ws-x="[$outline]">
            <ws-flex>
                <button ws-x="[$fill] [$color primary] [r 8px]">
                    Click Me!
                </button>
                <div ws-x="[w 100px] [h 200px] [bg.c teal]"></div>
            </ws-flex>
        </ws-paper>
    </ws-screen>
</body>
<!-- Normal pages work fine -->
<body ws-x="@@theme:tron">
    <script src="<windstorm>"></script>
    <ws-paper ws-x="[$outline]">
        <ws-flex>
            <button ws-x="[$fill] [$color primary] [r 8px]">
                Click Me!
            </button>
            <div ws-x="[w 100px] [h 200px] [bg.c teal]"></div>
        </ws-flex>
    </ws-paper>
</body>

API

Windstorm has a few utility functions for making dynamic ws-x declarations easier, and making custom functions simpler.

x(object)

The x function takes in an object where each [key, value] pair will be converted into a valid string for the ws-x attribute, including formatting markers correctly. The value can take one of a few forms, and which form it takes will affect the output:

  • A string that will be used as the arg string
    [key, value] -> "[key value]", [@@key, value] -> "@@key:value"
  • true (boolean) will output the function without an arg string
    [key, true] -> "[key]", [@@key, true] -> "@@key"
  • null, false, or undefined will output nothing, useful for making something that is toggled or catching when something isn't defined.
    [key, value] -> ""
// returns "@@button [$outline] [r 4px] [b 1px solid @main-color] [@var 10px]"
ws.x({
    "@@button": true,
    $outline: true,
    r: "4px",
    hide: false,
    b: "1px solid @main-color",
    "@var": "10px",
})