Getting Started

Everything you need to know to use the dotHello v1.8.1 framework in your own project.

Contents

  1. What is dotHello?
  2. Quick start
  3. File structure
  4. Customising tokens
  5. Light-background pages
  6. Components reference
  7. JS behaviours
    1. Initialization
    2. Scroll reveal
    3. Dark mode
    4. Audio player
    5. Countdown timer
    6. Tabs
    7. Accordion
    8. Modals
    9. Dropdowns
    10. Lightbox & gallery
    11. Progress bars
    12. Skeleton loaders
    13. Form validation
    14. Toast notifications
    15. Video embed
    16. Parallax
    17. Lottie animations
    18. Smooth scroll
    19. Panel transitions
    20. Code copy
    21. Auto-contrast
    22. Contrast utilities
  8. Dashboard addon
    1. Load order
    2. Charts
    3. Tables
    4. Layout
    5. Initialization

1. What is dotHello?

dotHello is a lightweight CSS and JS framework for dark-mode-first microsites — landing pages, digital business cards, product pages, and small web apps. It gives you a set of well-designed components out of the box, driven entirely by CSS custom properties so you can brand it in minutes.

2. Quick start

Option A — Use files from this kit (local / self-hosted)

Copy the css/ and js/ folders into your project, then add to your HTML <head> and just before </body>:

HTML — <head> links
<link rel="stylesheet" href="css/dothello.css">
<link rel="stylesheet" href="css/tokens.css">
HTML — before </body>
<script src="js/dothello.js"></script>
<script>DH.init();</script>

Option B — CDN (no download needed)

HTML — CDN links
<link rel="stylesheet" href="https://hellodjt.com/dh/dothello.css">
<link rel="stylesheet" href="https://hellodjt.com/dh/tokens.css">
<!-- before </body> -->
<script src="https://hellodjt.com/dh/dothello.js"></script>
<script>DH.init();</script>
Tip: DH.init() calls every init* function at once. Place the <script> tag at the end of <body> (not with defer) so the DOM is fully parsed before DH.init() runs. Open demo/index.html to see every component working live.

3. File structure

4. Customising tokens

Open css/tokens.css and change the values in the :root block. The most important token is --dh-color-primary — update it to your brand colour and buttons, links, and highlights all update automatically.

css/tokens.css — minimum customisation
:root {
  --dh-color-primary:   #your-colour;          /* brand accent */
  --dh-font-body:       'Your Font', sans-serif;
  --dh-color-dark:      #your-dark-bg;          /* page background */
}

The kit's tokens.css has every token listed with comments explaining what it does. The key tokens are:

TokenDefault in kitUse
--dh-color-primary#f59e0bButtons, links, highlights, active states
--dh-color-dark#0f0f0fPage background (dark)
--dh-color-dark-soft#1a1a1aAlt section backgrounds
--dh-color-dark-mid#222Card and panel backgrounds
--dh-color-text-inverse#f0f0f0Text on dark surfaces
--dh-color-text-muted#6b7280Secondary / hint text
--dh-font-bodyInter, system-uiBody typeface
--dh-shadow-glowamber radial glowHero glow — update to match primary
--dh-radius10pxCard and box border-radius

5. Light-background pages

dotHello is dark-mode first. The framework and tokens.css set a dark background and light text by default. For a light-background page (like this guide), add a page-level override in your own <style> block:

Your page <style> block
/* Override dark-mode tokens for this page */
:root {
  --dh-color-text:       #1c1c1c;
  --dh-color-text-muted: #6b7280;
}
body { background: #f5f5f5; color: #1c1c1c; }
Important: Always hardcode the body color value on light pages — do not use var(--dh-color-text) there, because the token resolves to the dark-mode value from tokens.css before your override takes effect.

Components like dh-nav and dh-app-header use var(--dh-color-dark) internally, so they keep their dark appearance even on a light-background page — which is usually the desired result.

6. Components reference

All components work by adding class names to standard HTML elements. Open demo/index.html to see them all rendered live. Below is the complete class reference.

Buttons

Navigation

Hero

Cards & data display

Layout & grid

Forms & inputs

App shell

Modal

Tabs

Accordion

Dropdown

Toast notifications

Progress bar

Skeleton loader

Countdown

Dark mode toggle

Logo bar

Section dividers

Lightbox

Audio player

7. JS behaviours

Include js/dothello.js at the end of <body> and call DH.init(). Every behaviour below is activated automatically when you call DH.init(). You can also call individual init* functions yourself if you only need specific features.

7.1 Initialization

DH.init() is a single convenience call that invokes all init* functions at once. Call it once at the end of <body> after your markup.

JavaScript
DH.init(); // activates all 28 behaviours in one call

// Or call individual functions:
DH.initScrollReveal();
DH.initModals();
DH.initTabs();

7.2 Scroll reveal

Add data-dh-reveal to any element. It will fade and animate in when it enters the viewport. Choose from several animation variants using the attribute value.

  • Variants: fade (default), slide-up, slide-down, slide-left, slide-right, zoom, flip
  • Add data-dh-stagger on a container to auto-delay each child element
  • Add data-dh-delay="200" (ms) on individual elements to set a custom delay
  • All elements are shown instantly if prefers-reduced-motion is active
HTML — scroll reveal variants
<!-- Default fade-in -->
<div data-dh-reveal>Fades in</div>

<!-- Slide up from below -->
<div data-dh-reveal="slide-up">Slides up</div>

<!-- Zoom in -->
<div data-dh-reveal="zoom">Zooms in</div>

<!-- Auto-staggered container -->
<div class="dh-grid-3" data-dh-stagger>
  <div class="dh-card--dark" data-dh-reveal="slide-up">Card 1</div>
  <div class="dh-card--dark" data-dh-reveal="slide-up">Card 2</div>
  <div class="dh-card--dark" data-dh-reveal="slide-up">Card 3</div>
</div>

<!-- Manual delay on a single element -->
<div data-dh-reveal="fade" data-dh-delay="400">Delayed 400 ms</div>

7.3 Dark mode

dotHello ships a complete dark-mode system. It reads localStorage and prefers-color-scheme on load, adds .dh-dark to <html> when dark mode is active, and persists the user's choice. Use the dh-dark-toggle element for a UI control, or drive it programmatically.

HTML — toggle button
<button class="dh-dark-toggle">
  <span class="dh-dark-toggle__icon"></span>
  <span class="dh-dark-toggle__label">Dark mode</span>
</button>
JavaScript — programmatic API
DH.getDarkMode();       // → true or false
DH.setDarkMode(true);   // force dark mode on
DH.setDarkMode(false);  // force light mode
DH.toggleDarkMode();    // flip the current state

7.4 Audio player

An auto-generated audio player with a track list. Use data-dh-audio="classic" for an iPod-style design or "modern" for a minimal bar style. Provide tracks as a JSON array in data-dh-audio-tracks.

HTML
<div data-dh-audio="classic"
     data-dh-audio-tracks='[
       {"title":"Track One","artist":"Artist Name","src":"audio/track1.mp3"},
       {"title":"Track Two","artist":"Artist Name","src":"audio/track2.mp3"}
     ]'>
</div>
Note: The src paths must point to real audio files. Supported formats: MP3, OGG, WAV.

7.5 Countdown timer

Add data-dh-countdown with an ISO 8601 date string. The timer counts down to that date and fires a dh:countdown:end custom event on the element when it reaches zero.

HTML
<div class="dh-countdown" data-dh-countdown="2026-12-31T00:00:00">
  <div class="dh-countdown__inner">
    <div class="dh-countdown__unit">
      <span class="dh-countdown__value">00</span>
      <span class="dh-countdown__label">Days</span>
    </div>
    <span class="dh-countdown__sep">:</span>
    <div class="dh-countdown__unit">
      <span class="dh-countdown__value">00</span>
      <span class="dh-countdown__label">Hours</span>
    </div>
    <span class="dh-countdown__sep">:</span>
    <div class="dh-countdown__unit">
      <span class="dh-countdown__value">00</span>
      <span class="dh-countdown__label">Minutes</span>
    </div>
    <span class="dh-countdown__sep">:</span>
    <div class="dh-countdown__unit">
      <span class="dh-countdown__value">00</span>
      <span class="dh-countdown__label">Seconds</span>
    </div>
  </div>
</div>

<!-- Listen for completion -->
<script>
  document.querySelector('.dh-countdown')
    .addEventListener('dh:countdown:end', () => console.log('Done!'));
</script>

7.6 Tabs

Add data-dh-tabs to a wrapper element. Tab buttons use data-tab attributes and panels use data-tab-panel. Arrow keys navigate between tabs and full ARIA roles are applied automatically.

HTML
<div data-dh-tabs>
  <div class="dh-tabs__nav">
    <button data-tab="tab1" class="is-active">Tab One</button>
    <button data-tab="tab2">Tab Two</button>
    <button data-tab="tab3">Tab Three</button>
  </div>
  <div data-tab-panel="tab1" class="is-active">Content for Tab One</div>
  <div data-tab-panel="tab2">Content for Tab Two</div>
  <div data-tab-panel="tab3">Content for Tab Three</div>
</div>

7.7 Accordion

Add data-dh-accordion for single-open mode or data-dh-accordion="multi" to allow multiple panels open at once. Each item needs a trigger button and a body panel.

HTML
<!-- Single open (default) -->
<div data-dh-accordion>
  <div class="dh-accordion__item">
    <button class="dh-accordion__trigger">Question one?</button>
    <div class="dh-accordion__body">Answer text goes here.</div>
  </div>
  <div class="dh-accordion__item">
    <button class="dh-accordion__trigger">Question two?</button>
    <div class="dh-accordion__body">Another answer here.</div>
  </div>
</div>

<!-- Multi-open -->
<div data-dh-accordion="multi">
  <!-- same item structure -->
</div>

7.8 Modals

Wire up a trigger button with data-dh-modal-open pointing to the modal's id. Close buttons inside use data-dh-modal-close. Clicking the backdrop or pressing Escape also closes. Full focus trap and ARIA applied automatically.

HTML
<!-- Trigger -->
<button class="dh-btn dh-btn--primary" data-dh-modal-open="my-modal">
  Open modal
</button>

<!-- Modal markup -->
<div id="my-modal" class="dh-modal">
  <div class="dh-modal__box">
    <h2 class="dh-modal__title">Modal title</h2>
    <p>Modal body content goes here.</p>
    <button class="dh-btn dh-btn--ghost-dark dh-btn--sm" data-dh-modal-close>
      Close
    </button>
  </div>
</div>

7.9 Dropdowns

Add data-dh-dropdown to the wrapper. The trigger button and content panel use the classes below. Escape or clicking outside closes the dropdown; arrow keys navigate items.

HTML
<div data-dh-dropdown class="dh-dropdown">
  <button class="dh-btn dh-btn--ghost-dark dh-dropdown__trigger">
    Options ▾
  </button>
  <div class="dh-dropdown__content">
    <a href="#">Edit</a>
    <a href="#">Duplicate</a>
    <a href="#">Delete</a>
  </div>
</div>

7.10 Lightbox & gallery

Add data-dh-lightbox to any <img> to make it openable in a full-screen lightbox. Group images into a gallery by wrapping them in a data-dh-gallery container — arrow keys and swipe then navigate between them.

HTML — single image
<img data-dh-lightbox src="photo.jpg" alt="A description">
HTML — gallery
<div data-dh-gallery class="dh-grid-3">
  <img data-dh-lightbox src="photo1.jpg" alt="Image 1">
  <img data-dh-lightbox src="photo2.jpg" alt="Image 2">
  <img data-dh-lightbox src="photo3.jpg" alt="Image 3">
</div>

7.11 Progress bars

Add data-dh-progress="75" (0–100) to a dh-progress element. Add data-dh-progress-animated to animate the bar in when it scrolls into view.

HTML
<!-- Static -->
<div class="dh-progress" data-dh-progress="65">
  <div class="dh-progress__bar"></div>
  <span class="dh-progress__label">65%</span>
</div>

<!-- Animated on scroll -->
<div class="dh-progress" data-dh-progress="90" data-dh-progress-animated>
  <div class="dh-progress__bar"></div>
  <span class="dh-progress__label">90%</span>
</div>

7.12 Skeleton loaders

Wrap skeleton placeholder elements in a container with data-dh-skeleton. JS will remove them after data-dh-skeleton-delay ms (default 2000). Call DH.removeSkeleton(el) programmatically when real data has loaded.

HTML
<div data-dh-skeleton data-dh-skeleton-delay="3000">
  <div class="dh-skeleton dh-skeleton--avatar"></div>
  <div class="dh-skeleton dh-skeleton--text"></div>
  <div class="dh-skeleton dh-skeleton--text" style="width:60%"></div>
  <div class="dh-skeleton dh-skeleton--card"></div>
</div>
JavaScript — remove when data is ready
fetch('/api/data').then(res => res.json()).then(data => {
  DH.removeSkeleton(document.querySelector('[data-dh-skeleton]'));
  // render real content…
});

7.13 Form validation

Add data-dh-validate to any <form> for automatic validation on submit with inline error messages. Add data-dh-validate="submit-only" to suppress real-time validation. Call DH.validateForm() programmatically for manual control.

HTML — auto validation
<form data-dh-validate>
  <div class="dh-form__group">
    <label class="dh-form__label" for="email">Email</label>
    <input class="dh-input" type="email" id="email" required>
    <div class="dh-form__error"></div>
  </div>
  <button class="dh-btn dh-btn--primary" type="submit">Submit</button>
</form>
JavaScript — programmatic
const form = document.querySelector('form');
DH.validateForm(form, { realtime: true, showErrors: true });

7.14 Toast notifications

Call DH.toast() from anywhere in your JS. The toast container is auto-created. Toasts auto-dismiss after duration ms (default 3500).

JavaScript
// Default (dark)
DH.toast('Changes saved.');

// Success
DH.toast('Profile updated!', { type: 'success', duration: 4000 });

// Error
DH.toast('Something went wrong.', { type: 'error' });

// Warning
DH.toast('Your session expires soon.', { type: 'warning', duration: 6000 });

7.15 Video embed

Add data-dh-video to any element with a youtube:VIDEO_ID or vimeo:VIDEO_ID value. A placeholder thumbnail is shown; clicking embeds the iframe with autoplay.

HTML
<!-- YouTube -->
<div data-dh-video="youtube:dQw4w9WgXcQ"></div>

<!-- Vimeo -->
<div data-dh-video="vimeo:148751763"></div>

7.16 Parallax

Add data-dh-parallax to any element to give it a parallax scrolling offset. Control the speed with data-dh-parallax-speed0 means no movement, 1 moves at full scroll speed. Default is 0.5.

HTML
<!-- Default speed (0.5) -->
<div data-dh-parallax>Subtle parallax</div>

<!-- Slow drift -->
<div data-dh-parallax data-dh-parallax-speed="0.2">Slow</div>

<!-- Fast drift -->
<div data-dh-parallax data-dh-parallax-speed="0.8">Fast</div>

7.17 Lottie animations

Add data-dh-lottie with the path to a .json animation file. Requires lottie-web to be loaded (via CDN or locally). Configure playback with the optional attributes below.

HTML — load lottie-web + animation
<!-- Load lottie-web before dothello.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lottie-web/5.12.2/lottie.min.js"></script>

<!-- Animation element -->
<div data-dh-lottie="animations/hero.json"
     data-dh-lottie-autoplay="true"
     data-dh-lottie-loop="true"
     data-dh-lottie-speed="1"
     data-dh-lottie-renderer="svg">
</div>

7.18 Smooth scroll

DH.initSmoothScroll() intercepts all <a href="#anchor"> links on the page and scrolls smoothly to the target element instead of jumping. No markup changes needed — it activates automatically via DH.init().

HTML — nothing special needed
<!-- Any anchor link is automatically smooth -->
<a href="#features">Jump to features</a>

<section id="features">...</section>

7.19 Panel transitions

DH.swapPanel(from, to, onShown) transitions between two visible panel elements with a smooth crossfade. Pass the two DOM elements and an optional callback fired after the new panel is visible.

JavaScript
const step1 = document.getElementById('step-1');
const step2 = document.getElementById('step-2');

document.getElementById('next-btn').addEventListener('click', () => {
  DH.swapPanel(step1, step2, () => {
    console.log('Step 2 is now visible');
  });
});

7.20 Code copy

Automatically injects a Copy button into every .dh-code-block. Clicking copies the code to the clipboard and shows a 2-second "Copied!" confirmation. Called by DH.init() — no setup required.

HTML
<div class="dh-code-block" data-dh-lang="JavaScript">
  <pre><code>console.log('hello');</code></pre>
</div>

The optional data-dh-lang attribute sets the language label displayed in the copy button.

7.21 Auto-contrast

Add data-dh-autotext to any element and dotHello will automatically pick a readable foreground colour based on the element's background. Works with solid colours, images (canvas sampling), and gradients (CSS blend fallback). Re-runs on every dark-mode toggle.

HTML
<!-- Solid background — YIQ contrast -->
<section class="dh-hero" data-dh-autotext>...</section>

<!-- Custom token overrides instead of #fff / #000 -->
<div style="background:#c8b560" data-dh-autotext
     data-dh-light="var(--dh-color-white)"
     data-dh-dark="var(--dh-color-dark)">...</div>

Tiers: (1) solid bg-color → YIQ formula · (2) bg-image → canvas pixel sampling · (3) gradient detected → dh-text--blend CSS class added automatically.

7.22 Contrast utilities

Public helper functions available on the DH namespace for use in template scripts.

JavaScript
// YIQ contrast — returns '#ffffff' or '#000000' (threshold 186)
DH.getContrastColor('#6C63FF');            // → '#ffffff'
DH.getContrastColor('#FFDD57', '#fff', '#1a1a1a'); // custom pair

// Convert computed color string to {r,g,b}
DH.parseRGB(getComputedStyle(el).backgroundColor);

// Walk DOM for nearest non-transparent background
DH.getEffectiveBg(document.querySelector('.dh-hero'));

// Convert r,g,b integers to hex string
DH.rgbToHex(108, 99, 255); // → '#6c63ff'

8. Dashboard addon

The dashboard addon is a separate CSS + JS pair that adds charts, sortable tables, stat trends, layout primitives, and a full 12-column dashboard grid. Load it after the core dotHello files.

8.1 Load order

HTML
<!-- 1. Core -->
<link rel="stylesheet" href="dothello.css">
<!-- 2. Dashboard addon -->
<link rel="stylesheet" href="dothello-dashboard.css">

<!-- 3. Core -->
<script src="dothello.js"></script>
<!-- 4. Dashboard addon -->
<script src="dothello-dashboard.js"></script>
<script>
  DH.init();           // core behaviours
  DH.initDashboard();  // charts + tables
</script>

8.2 Charts

SVG charts rendered from inline JSON via data-dh-chart. Supported types: line, area, bar, donut. All charts include hover tooltips and automatically pick colours from the --dh-chart-0--dh-chart-11 CSS token cycle.

HTML
<div data-dh-chart="area"
     data-dh-chart-data='{
       "labels": ["Jan","Feb","Mar","Apr","May","Jun"],
       "datasets": [
         { "label": "Visitors", "values": [1200,1800,1600,2400,2100,2800] }
       ]
     }'
     style="height:220px"></div>

For donut charts, supply a single dataset with an optional "colors" array to override the auto palette.

8.3 Tables

Add data-dh-table to a <table> and data-dh-sort to any <th> to make columns sortable. Wire up a search input with data-dh-table-filter="tableId".

HTML
<input class="dh-table__search" data-dh-table-filter="pages-table"
       placeholder="Filter…">

<div class="dh-table-wrap">
  <table class="dh-table" data-dh-table id="pages-table">
    <thead>
      <tr>
        <th data-dh-sort>Page</th>
        <th data-dh-sort>Views</th>
        <th>Trend</th>
      </tr>
    </thead>
    <tbody>
      <tr><td>/home</td><td>4821</td>
          <td><span class="dh-badge--trend dh-badge--trend-up">↑ 12%</span></td></tr>
    </tbody>
  </table>
</div>

8.4 Layout

Use .dh-dashboard-grid with .dh-col-* span helpers (1–12) for responsive 12-column layouts. Collapses to single column below 640 px.

HTML
<div class="dh-dashboard">
  <!-- Sidebar (from dothello.css) -->
  <aside class="dh-sidebar">...</aside>

  <!-- Main content -->
  <main class="dh-dashboard__main">
    <header class="dh-topbar">
      <span class="dh-topbar__title">Analytics</span>
    </header>

    <div class="dh-dashboard-grid">
      <div class="dh-col-3"><!-- stat card --></div>
      <div class="dh-col-3"><!-- stat card --></div>
      <div class="dh-col-3"><!-- stat card --></div>
      <div class="dh-col-3"><!-- stat card --></div>
      <div class="dh-col-8"><!-- line chart --></div>
      <div class="dh-col-4"><!-- donut chart --></div>
      <div class="dh-col-12"><!-- table --></div>
    </div>
  </main>
</div>

8.5 Initialization

JavaScript
DH.initDashboard();          // runs initCharts() + initDashboardTables()

// Or individually:
DH.initCharts();             // render all [data-dh-chart] elements
DH.initDashboardTables();    // wire all [data-dh-table] elements

See dashboard-demo.html for a fully working example with stat cards, area chart, bar chart, donut, and sortable table.