Skip to content
/ themex Public

Flexible and unstyled theming system that supports multiple theme attributes with persistent storage and automatic UI synchronization.

Notifications You must be signed in to change notification settings

netoum/themex

Repository files navigation

Logo

Themex (@netoum/themex)

Flexible and unstyled theming system that supports multiple theme attributes with persistent storage and automatic UI synchronization.

Features

  • 🎨 Multiple theme attributes support (color schemes, modes, layouts, etc.)
  • πŸ’Ύ Automatic localStorage persistence
  • πŸ”„ UI state synchronization across controls
  • 🎯 Data attribute-based targeting
  • πŸ“± Support for various control types (select, button, checkbox, radio and range)
  • πŸ”Œ Zero dependencies
  • πŸ“¦ CommonJS & ESM support

Installation

npm install @netoum/themex

Quick Start

import { Themex } from '@netoum/themex';

const options = [
  {
    key: 'theme',
    default: 'gray',
    values: ['gray', 'red']
  },
  {
    key: 'mode',
    default: 'light',
    values: ['light', 'dark']
  },
  {
    key: 'density',
    default: 'compact',
    values: ['compact', 'wide']
  },
    {
    key: 'size',
    default: '2',
    values: ['1', '2', '3']
  }
];

new Themex(options);

Data Attributes

  • data-${key}: Applied to HTML document (for ex: data-mode="dark")
  • data-themex-key: Identifies the theme attribute to modify
  • data-themex-value: Specifies the value to apply

State Attributes

  • aria-current: Applied to Button Set controls to indicate current selection
  • aria-pressed: Applied to Button Toggle controls to indicate current selection
  • data-selected: Applied to Select Options controls to indicate current selection

HTML Controls

Themex works with various HTML controls:

Button Set

You must add "set" to each button The selected button will have "aria-current="true" attribute

<button data-themex-key="mode" data-themex-value="light" set>
  Light
</button>
<button data-themex-key="mode" data-themex-value="dark" set>
  Dark
</button>

<div role="button" data-themex-key="mode" data-themex-value="light" set>
  Light
</div>
<div role="button" data-themex-key="mode" data-themex-value="dark" set>
  Dark
</div>
button[aria-current="true"] {
  background-color: var(--color-primary-contrast);
  color:  var(--color-primary);
}

div[role="button"][aria-current="true"] {
  background-color: var(--color-primary-contrast);
  color:  var(--color-primary);
}

Button Toggle

You must add "toggle" to each button The selected button will have "aria-pressed="true" attribute

<button data-themex-key="mode" data-themex-value="light" toggle>
  Light
</button>
<button data-themex-key="mode" data-themex-value="dark" toggle>
  Dark
</button>

<div role="button" data-themex-key="mode" data-themex-value="light" toggle>
  Light
</div>
<div role="button" data-themex-key="mode" data-themex-value="dark" toggle>
  Dark
</div>
button[aria-pressed="true"] {
  display: hidden
}

div[role="button"][aria-pressed="true"] {
  display: hidden
}

Select Dropdowns

By default Select do not have a common way to track the selected option on all browser, so we add "data-selected="true" attribute for styling

<select data-themex-key="theme">
    <option value="gray">Gray</option>
    <option value="red">Red</option>
</select>
option[data-selected="true"] {
  background-color: var(--color-primary-contrast);
  color:  var(--color-primary);
}

Switches/Checkbox Toggle

You must select 2 values, the first one being the value selectd when the checkob is checked, the second beign the fallback when the checkbox is unchecked

<label>
  Wide
</label>
  <input type="checkbox" 
         data-themex-key="density" 
         data-themex-value="wide,compact">

Radio

      <label>
        Gray Theme
      </label>
      <input type="radio" name="theme-radio" data-themex-key="theme" data-themex-value="gray">
      <label>
        Red Theme
      </label>
      <input type="radio" name="theme-radio" data-themex-key="theme" data-themex-value="red">

CSS Usage

:root {
    /* Theme */
    --color-primary: var(--theme-color-primary);
    --color-primary-contrast: var(--theme-color-primary-contrast);

    /* Theme/Mode */
    --color-body: var(--theme-color-body);
    --color-body-contrast: var(--theme-color-body-contrast);

    /* Density */
    --spacing: var(--density-spacing);

    /* Base */
    --color-gray-1: #f6f6f6;
    --color-gray-2: #e2e2e2;
    --color-gray-3: #8b8b8b;
    --color-gray-4: #6f6f6f;
    --color-gray-5: #3e3e3e;
    --color-gray-6: #222222;
    --color-red-1: #fff8f6;
    --color-red-2: #ffddd8;
    --color-red-3: #ff4647;
    --color-red-4: #e0002b;
    --color-red-5: #830014;
    --color-red-6: #530003;
}

/* Theme variations */

[data-theme="gray"] {
  --theme-color-primary: var(--color-gray-2);
  --theme-color-primary-contrast: var(--color-gray-6);
}


[data-theme="red"] {
  --theme-color-primary: var(--color-red-2);
  --theme-color-primary-contrast: var(--color-red-6);
}

/* Theme/Mode variations */

[data-theme="gray"][data-mode="light"] {
--theme-color-body: var(--color-gray-2);
--theme-color-body-contrast: var(--color-gray-6);
}


[data-theme="gray"][data-mode="dark"] {
--theme-color-body: var(--color-gray-6);
--theme-color-body-contrast: var(--color-gray-2);

}

[data-theme="red"][data-mode="light"] {
--theme-color-body: var(--color-red-2);
--theme-color-body-contrast: var(--color-red-6);
}


[data-theme="red"][data-mode="dark"] {
--theme-color-body: var(--color-red-6);
--theme-color-body-contrast: var(--color-red-2);

}


/* Density variations */
[data-density="compact"] {
--spacing: 0.5rem;
--font-size: 0.875rem;
}

[data-density="wide"] {
--spacing: 1rem;
--font-size: 1rem;
}

/* See it in action */
body {
  background-color: var(--theme-color-body);
  color: var(--theme-color-body-contrast);
  padding: var(--spacing); 
  font-size: var(--font-size); 
}

button[aria-current="true"] {
  text-decoration: underline;
}

Examples

You will find some Themex examples with Vite and Eleventy using more complex theming and referencing. Some example also uses the System mode for Light/Dark mode

License

MIT

Open source by Netoum

The whole project, including the examples are fully open source and brought to you by Netoum.com

About

Flexible and unstyled theming system that supports multiple theme attributes with persistent storage and automatic UI synchronization.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published