Skip to content

Lifecycle

The engine has three phases: load, first scan, and observation. This page walks through each.

1. Load

When chai.js is parsed, the UMD wrapper:

  1. Reads the default theme.
  2. Defines the rules array.
  3. Reads data-chai-* attributes from document.currentScript.
  4. Reads meta[name="chai-config"] (JSON).
  5. Constructs window.chai = new Chai(config).
  6. If autoStart !== false, calls chai.start().

If autoStart is false, nothing happens until you call it yourself.

2. First scan

chai.start() schedules chai.scan(document.body) for DOMContentLoaded (or runs it immediately if the document is already past loading). The scan:

  1. Walks every descendant of <body> via querySelectorAll('*').
  2. For each element, calls chai.apply(el).
  3. apply reads el.classList, parses every chai-* class, merges the resulting style objects, and writes them via style.setProperty(...).
  4. Unless keepClasses is true, the matched classes are removed.

This runs once per start() call. The scan returns the number of classes successfully applied.

3. Observation

After the first scan, if observe is true, a MutationObserver is attached to document.body watching:

  • childList (subtree: true) — for any addedNodes, the engine calls scan(node) so newly inserted DOM is styled.
  • attributes (filter: class) — for any element whose class attribute changes, the engine calls apply(el).

A _mutating flag is flipped during the engine’s own writes so its own class-removal doesn’t trigger an infinite loop.

Stopping

chai.stop() disconnects the observer. Already-applied inline styles remain on the elements. New nodes added after stop() won’t be styled until you start() again or call scan(node) manually.

Manual control

You can run chaiTailwind in fully-manual mode by disabling auto-start and observation:

<script src="chai.js" data-chai-auto-start="false" data-chai-observe="false"></script>
<script>
// …construct or append your DOM…
window.chai.scan(document.body); // explicit, one-shot pass
</script>

Or programmatically:

import { Chai } from 'chaitailwind';
const chai = new Chai({ autoStart: false, observe: false });
// later, after your framework has rendered:
chai.scan(document.getElementById('root'));

Hot-reloading the engine

If you change the theme at runtime, re-scan to apply the new values:

chai.theme.colors.brand = '#ff0000';
chai.scan(); // re-resolves chai-bg-brand etc.

(Re-scanning is idempotent and overwrites inline styles.)

Made by Saad · @developedbysaad on X