Skip to content
Docs version
@hungpvq/vue-map@1.1.0@hungpvq/vue-map-core@1.1.0@hungpvq/vue-map-dataset@1.1.0@hungpvq/vue-map-draw@1.1.0@hungpvq/map-draw@1.1.0@hungpvq/react-map@1.1.0@hungpvq/react-map-core@1.1.0@hungpvq/react-map-dataset@1.1.0@hungpvq/react-map-draw@1.1.0

ThemeControl

Usecase

  • Switch map UI chrome (sidebar / popup / card overlays) across named themes.
  • Click the main button to toggle light ↔ dark based on the currently resolved theme’s color scheme.
  • Hover (or keyboard focus within the group) to open a menu of configured themes, including Auto.

Scope

scopeClassesStorageMulti-map
document (default)html.map-theme-* and mirror on this map’s .map-container[data-map-id]hungpvq.map-theme-modeOne preference for the page
mapOnly .map-container[data-map-id]hungpvq.map-theme-mode:<mapId>Independent theme per map

Use scope="map" when multiple maps on one page need different chrome themes. UI teleported outside that container still follows the document (html) theme unless you also bootstrap a document theme.

When the OS requests more contrast (prefers-contrast: more), the control / bootstrapMapTheme also toggles .map-theme-contrast (stronger borders and focus rings). Live updates use subscribePrefersContrastMore.

Behavior

Click (main button)

  1. Resolve the current mode (resolveMapTheme(mode)).
  2. If MAP_THEME_COLOR_SCHEME[resolved] === 'dark' → set mode to 'light', otherwise → 'dark'.

Examples: auto resolving to dark → click sets light; vibrant / ocean (light scheme) → click sets dark; slate → click sets light.

The main icon shows the target of that toggle (sun when the current scheme is dark, moon when light).

Hover / focus-within

Expands a row button group listing every mode in the themes prop. Pick a theme to set mode, persist, and apply. The active item matches the stored mode (auto is active only when mode is auto).

ModeBehavior
autoResolves to light or dark via prefers-color-scheme
lightNeutral white chrome + blue
darkCharcoal overlay + sky blue
vibrantLavender panels + purple / magenta
oceanAqua panels + teal / cyan
forestSage panels + green
sunsetPeach panels + coral / amber
slateSteel dark overlay + cyan accent

Bootstrap without the control:

ts
import { bootstrapMapTheme } from '@hungpvq/map-core/theme';

bootstrapMapTheme('auto');
// or force a named theme:
bootstrapMapTheme('vibrant');

// Per-map bootstrap (no html change):
bootstrapMapTheme('dark', { scope: 'map', mapId: 'my-map' });

Helpers: MAP_THEME_IDS, MAP_THEME_MODES, resolveMapTheme, applyMapTheme / applyMapThemeClass / applyMapThemeForMap, toggleMapThemeLightDark, normalizeMapThemeModes, getMapThemeStorageKey.

Props

PropTypeDefaultDescription
themesMapThemeMode[]MAP_THEME_MODESModes shown in the hover menu. Invalid ids are filtered out.
scope'document' | 'map''document'Where theme classes + preference are applied.
PropDescriptionTypeRequiredDefault Value
mapIdstringfalse--
dragIdstringfalse--
btnWidthnumberfalse40
controlOrderCSS flex order for the standalone buttonnumberfalse0
position'top-left', 'top-right', 'bottom-left', 'bottom-right'false'bottom-right'
controlLayout'standalone' (corner), 'toolbar' (always in toolbar), 'button' (always corner; not auto-promoted on mobile)'standalone' | 'toolbar' | 'button'false'standalone'
controlVisiblebooleanfalsetrue

Map also accepts buttonInMobile ('button' | 'toolbar' | 'menu', default 'button'). On viewports ≤640px:

  • 'button' — leave corner buttons unchanged
  • 'toolbar' — move declared control buttons into a single ToolbarControl host (except controlLayout="button"). Mount one ToolbarControl in the map slot
  • 'menu' — hide per-control corner buttons; fan out intact clusters by position into corner stacks with outside-in More. Mount one ToolbarControl.

See ToolbarControl.

Limit which themes appear:

tsx
<ThemeControl themes={['auto', 'light', 'dark', 'vibrant']} />
vue
<ThemeControl :themes="['auto', 'light', 'dark', 'vibrant']" />

Multi-map independent themes:

vue
<Map map-id="a"><ThemeControl scope="map" /></Map>
<Map map-id="b"><ThemeControl scope="map" /></Map>
tsx
<Map mapId="a"><ThemeControl scope="map" /></Map>
<Map mapId="b"><ThemeControl scope="map" /></Map>

Usage

Vue

vue
<script setup lang="ts">
import { Map, ThemeControl } from '@hungpvq/vue-map-core';
import '@hungpvq/vue-map-core/style.css';
</script>

<template>
  <Map>
    <ThemeControl />
    <!-- or: <ThemeControl scope="map" /> -->
  </Map>
</template>

React

tsx
import { Map, ThemeControl } from '@hungpvq/react-map-core';
import '@hungpvq/react-map-core/style.css';

export function App() {
  return (
    <Map>
      <ThemeControl />
      {/* or: <ThemeControl scope="map" /> */}
    </Map>
  );
}