← All posts

Action types

TOGGLE3: 3-state segmented control in the action bar — Dev/Staging/Prod, Light/Dark/Auto

A button is "click → run". A select is "pick one of N". What about "three known states" — because you have Dev/Staging/Prod, or Light/Dark/Auto, or Off/Default/Force-on? That's TOGGLE3 (since v2.13.25) — a 3-state segmented control with its own colour for each state and JS code that fires on state change.

Why a separate type and not select / button?

TypeState countUXActive state memory
BUTTON1 (click = run)Single buttonNone — fire-and-forget
SELECT static2-N (dropdown)List on clickYes (dataset)
TOGGLE3Exactly 33 buttons side-by-sideYes (index 0/1/2)
INPUT / TEXTAREAFree-textText fieldYes (el.value)

Three states fit perfectly into an "iOS segmented control" pattern — all 3 visible at once, one is active, clicking another swaps active state. No dropdown, no surprises. Classic mobile UX.

First TOGGLE3 action — Light / Dark / Auto

Add a TOGGLE3 action to the action bar, with 3 states:

states[0] = { label: 'Light', value: 'light' }
states[1] = { label: 'Auto',  value: 'auto'  }
states[2] = { label: 'Dark',  value: 'dark'  }
defaultStateIdx: 1   // Auto on first visit

In the "Code" field:

// `value`, `stateIdx`, `stateLabel` are injected as const before your code.
const html = document.documentElement;
if (value === 'light') {
  html.style.colorScheme = 'light';
  html.removeAttribute('data-theme');
} else if (value === 'dark') {
  html.style.colorScheme = 'dark';
  html.setAttribute('data-theme', 'dark');
} else {
  html.style.colorScheme = '';
  html.removeAttribute('data-theme');
}
JUSTZIX.log(`Theme → ${stateLabel} (idx ${stateIdx})`);

Click "Dark" → the action changes HTML, click "Light" → code fires again with a new value. Active state has the full colour (from action.color), inactive ones are dimmed (from colorInactiveText).

5 colours — each state gets its own visual identity

Since v2.13.32 TOGGLE3 has 5 configurable colours (more than any other action type):

PropertyWhat it coloursDefault
colorActive state backgroundAction's default colour
colorTextActive state textWhite
colorBgWrap container background (the whole segment)Semi-transparent black
colorHoverInactive state hover backgroundfilter:brightness off colorBg
colorInactiveTextInactive states textrgba(255,255,255,0.55)

Use case: Dev/Staging/Prod where each active state has its own semantic colour (green / amber / red), but the wrap background and inactive text stay neutral so they don't mix. A red "Prod" state pops out visually — that's the whole point.

Use case 1 — Environment switcher Dev/Staging/Prod

You have an app with 3 environments under the same paths. Until now: manual URL editing, or bookmarks. TOGGLE3 with code:

// Each state has value = subdomain
states[0] = { label: 'DEV',  value: 'dev.app.com' }     // color: green
states[1] = { label: 'STG',  value: 'staging.app.com' } // color: amber
states[2] = { label: 'PROD', value: 'app.com' }         // color: red

// Code:
const newHost = value;
const path = location.pathname + location.search;
location.href = `https://${newHost}${path}`;

Click "PROD" → you jump to production preserving path + query. Memory holds the active state, so after reload you land in the same environment (defaultStateIdx only acts as a fallback on the first entry — memory wins).

Use case 2 — Feature flag tri-state

Your app reads a feature flag from localStorage. Three realistic states: "Off" (force-off), "Default" (server-driven), "Force on".

states[0] = { label: 'OFF',     value: 'off'     }
states[1] = { label: 'DEFAULT', value: 'default' }
states[2] = { label: 'FORCE',   value: 'force'   }

// Code:
if (value === 'default') {
  localStorage.removeItem('ff_newCheckout');
} else if (value === 'off') {
  localStorage.setItem('ff_newCheckout', 'false');
} else {
  localStorage.setItem('ff_newCheckout', 'true');
}
location.reload();  // Apply on reload
JUSTZIX.log(`Feature flag → ${stateLabel}`);

QA scenario: in 2 seconds switch a feature flag, verify the view, revert to default. All without devs and without DevTools console.

Use case 3 — Drive from another action via JZ.setValue

You have TOGGLE3 "Theme" (Light/Auto/Dark). And a second BUTTON action "🌙 Night mode" in another bar, which should be a script that sets Dark + hides banners + decreases font-size:

// BUTTON "Night mode" — Code:
JZ.setValue('Theme', 'dark');   // → activates state idx 2 + runs its code
document.body.style.fontSize = '14px';
document.querySelectorAll('.cookie-banner, .promo')
  .forEach(el => el.style.display = 'none');
JUSTZIX.log('Night mode activated.');

Works by value — JZ.setValue('Theme', 'dark') finds the state with value='dark'; or by label — JZ.setValue('Theme', 'Dark') case-insensitive; or numerically — JZ.setValue('Theme', 2). All paths converge on the same state.

Pitfalls

What's next

TOGGLE3 is the action type with the richest "UX identity" — per-state colours, persistence, built-in scope for 3-state decisions. Check also window.JZ helpers for programmatic state control from other actions and DEV/STG/PROD CSS markers as a visual companion for the environment switcher.

Install JustZix — completely free, no server, no account.

Rate this post

No ratings yet — be the first.

Try it yourself

Install JustZix and paste any snippet from this article. Two minutes from zero to a working rule across all your devices.

Get JustZix

Features · How it works · Examples · Use cases