SMARTi watermark
Drag & Drop Card Wiki · Section 07

Built-in DDC Cards

A comprehensive and user-friendly guide to creating modern, polished, and fully responsive Home Assistant dashboards using the Drag & Drop Card. This wiki combines clear explanations, practical real-world configuration examples, step-by-step walkthroughs, and visual references where they add the most value — making it easy for both beginners and advanced users to design powerful and visually appealing dashboards.

12 sections Config examples HADS-ready exports
Demo focus
Drag, resize, snap, export.
Add screenshots from admin to turn this section into a richer visual guide.

Built-in DDC Cards

Drag & Drop Card includes several helper cards that can be used inside the canvas. These are useful when you want dashboard-specific building blocks without installing another custom card.

HTML Card

The HTML card is for custom markup, CSS, and small scripts. Use it for highly customized dashboard elements, but keep the code focused and avoid turning it into a full application unless that is really needed.



This card is quite revolutionary as it gives users the full flexibility of web-design, look and feel. with this you can create 

cards like this:


A custom Energy Card


A custom Media Player Card


Persisting Runtime Config in an HTML card

The HTML card can contain its own UI, JavaScript, and local configuration controls. A common pattern is to add a config button inside the HTML card itself, so users can edit widget-specific settings without opening the Drag & Drop Card editor.

However, developers should be careful about where those settings are stored.

The Problem


Storing widget settings only in `localStorage` is not durable enough.

`localStorage` survives normal reloads, but it may be removed when the user clears browser cache/site data, changes browser/device, or resets Home Assistant frontend storage.

For settings that should survive a clear cache, the HTML card must write its runtime configuration back into the saved Drag & Drop Card layout.

Recommended Pattern


Store widget-specific settings as a custom field on the `custom:ddc-html-card` config.

Example:{ "type": "custom:ddc-html-card", "html": "...", "css": "...", "js": "...", "neo_score_config": { "entity": "sensor.smarti_hourly_energy_consumed", "label": "Energy used", "min": "0", "max": "10000", "unit": "kWh" } }
The HTML card JavaScript should:

Read from config.neo_score_config on startup.
Fall back to localStorage only for migration or emergency recovery.
When the user clicks Apply, write the new values back into the card config.
Update DDC’s wrapper config cache.
Ask DDC to save the layout.

Runtime Objects Available

Inside custom:ddc-html-card JavaScript, developers can use:

root // HTML content root host // the ddc-html-card element config // current card config hass // Home Assistant object ddc // Drag & Drop Card local dashboard API

The ddc API exposes helpers such as:

ddc.saveLayout(true); ddc.settings.get(key); ddc.settings.set(key, value, { persist: true });

For widget-specific config, prefer writing to the card config itself rather than dashboard-level settings.

Durable Save Example

This pattern writes internal widget settings into the saved HTML card config.

const CONFIG_FIELD = 'neo_score_config'; function getCardWrapper() { return host?.closest?.('.card-wrapper') || null; } function cloneJson(value, fallback = null) { try { return JSON.parse(JSON.stringify(value)); } catch { return fallback; } } function readSourceCardConfig() { const wrap = getCardWrapper(); try { const parsed = JSON.parse(wrap?.dataset?.cfg || 'null'); if (parsed && typeof parsed === 'object') return parsed; } catch {} if (host?.__ddcSourceConfig) { return cloneJson(host.__ddcSourceConfig, host.__ddcSourceConfig); } if (host?._config) { return cloneJson(host._config, host._config); } return cloneJson(config, config) || { type: 'custom:ddc-html-card' }; } async function saveWidgetConfig(values) { const wrap = getCardWrapper(); const source = readSourceCardConfig(); const nextConfig = { ...source, type: source.type || 'custom:ddc-html-card', [CONFIG_FIELD]: values }; // Update DDC's runtime/card config references. try { config[CONFIG_FIELD] = values; } catch {} try { host.__ddcSourceConfig = cloneJson(nextConfig, nextConfig); } catch {} try { if (host._config && typeof host._config === 'object') { host._config = { ...host._config, [CONFIG_FIELD]: values }; } } catch {} try { if (wrap?.dataset) { wrap.dataset.cfg = JSON.stringify(nextConfig); } } catch {} // Update responsive layout memory when available. try { const cardId = wrap?.dataset?.layoutCardId; if (cardId && ddc?.card?._updateCardConfigAcrossResponsiveLayouts_) { ddc.card._updateCardConfigAcrossResponsiveLayouts_(cardId, nextConfig); } } catch {} // Save the layout. try { await ddc?.saveLayout?.(true); } catch {} // Storage-dashboard persistence fallback, when available. try { await ddc?.card?._persistThisCardConfigToStorage_?.(); } catch {} }

Reading the Config on Startup

Always prefer the durable card config first:

function readWidgetConfig() { if (config?.neo_score_config) { return config.neo_score_config; } // Optional migration fallback only. try { return JSON.parse(localStorage.getItem('my-widget-config') || 'null'); } catch { return null; } }

Important Limitation

This only survives a clear cache if the Drag & Drop Card layout itself is saved outside browser-local storage.

Durable persistence requires one of:

  • DDC backend storage
  • Home Assistant Storage dashboard save
  • YAML/storage persistence supported by the dashboard setup

If the whole DDC layout exists only in browser-local state, then no HTML-card script can preserve settings after clearing site data.

Best Practices

Use localStorage only as a fallback, not as the source of truth.

Use a namespaced custom config field, for example:

neo_score_config weather_ring_config room_panel_config

Keep values JSON-safe: strings, numbers, booleans, arrays, and plain objects.

After saving internal config, update:

host.__ddcSourceConfig host._config wrap.dataset.cfg

Then call:

await ddc.saveLayout(true);

For widgets that also store default values in HTML data-* attributes, update the saved HTML string too. This makes exported/imported card JSON easier to inspect and keeps the visual markup aligned with the config object.

Summary

For cache-resistant HTML-card settings:

  • Do not rely only on localStorage.
  • Store runtime settings in the card config.
  • Sync the updated config into DDC’s wrapper cache.
  • Save the DDC layout.
  • Keep localStorage only as a migration fallback.

Text Card

The text card is for labels, headings, short notes, and rich text blocks. It is useful for dashboard titles, room labels, section headers, and short explanations.

Example:


Icon Card

The icon card is for large visual state indicators. It can react to Home Assistant entity state and is useful for lights, locks, media, climate, security, and status displays.

Table Card

The table card is for compact information layouts. Use it for room summaries, battery lists, schedules, sensor grids, or control rows.


Last updated 2026-05-29.