127 lines
5.1 KiB
Markdown
127 lines
5.1 KiB
Markdown
# Bubble Card Pop-up Migration — v3.2.0 Standalone Format
|
|
|
|
Session: 2026-07-10. Part of the HA dashboard redesign. All 5 pop-ups in the "Haus" dashboard were migrated from legacy format to the new standalone format.
|
|
|
|
## What Changed
|
|
|
|
Bubble Card v3.2.0 introduced standalone pop-ups. Legacy pop-ups (content cards as siblings in the view) must be migrated to standalone format (content cards nested inside the pop-up's `cards:` property).
|
|
|
|
Benefits of standalone format:
|
|
- Faster rendering
|
|
- More reliable display
|
|
- No longer need to live inside a vertical-stack card
|
|
- New editor based on HA section editor (drag-and-drop)
|
|
- New features: centered mode, classic style, performance mode
|
|
|
|
## ⚠️ CRITICAL PITFALL: Pop-up Migration Broke Tab Rendering
|
|
|
|
Moving content cards INTO the pop-up's `cards:` property (as the v3.2.0 migration instructs) caused **all views to render as empty/blank**. The user reported "die tabs sind leer" (the tabs are empty). The pop-up acts as an overlay — its content is hidden until the pop-up is triggered (hash navigation). When using Bubble Card `bottom-navigation` for tab switching, the pop-up is redundant and its content cards become invisible.
|
|
|
|
### Fix Applied
|
|
|
|
Removed all `card_type: 'pop-up'` cards from every view entirely. Content cards stay at view level as siblings of the `bottom-navigation` card. This works correctly — tabs show their content, bottom-navigation switches between views.
|
|
|
|
### Lesson
|
|
|
|
The v3.2.0 "standalone pop-up" format is designed for pop-ups that open/close on demand (hash-triggered overlays). If you're using `bottom-navigation` for persistent tab navigation (not pop-up overlays), do NOT use pop-up cards at all — just put content cards directly in the view alongside the `bottom-navigation` card. The migration notice is misleading for this use case.
|
|
|
|
### Final Working Structure
|
|
|
|
```yaml
|
|
views:
|
|
- title: Home
|
|
path: home
|
|
cards:
|
|
# NO pop-up card — just content + navigation
|
|
- type: custom:mushroom-template-card
|
|
primary: "{{ states('weather.forecast_home') }}"
|
|
...
|
|
- type: custom:power-flow-card-plus
|
|
...
|
|
- type: custom:bubble-card
|
|
card_type: bottom-navigation
|
|
routes:
|
|
- icon: mdi:home
|
|
name: Home
|
|
target: "#home"
|
|
- icon: mdi:window-shutter
|
|
name: Rollos
|
|
target: "#rollos"
|
|
# ...more routes
|
|
```
|
|
|
|
### Migration Script (WebSocket) — FOR REFERENCE ONLY
|
|
|
|
This script moves cards into the pop-up. **Do NOT use it if you're using bottom-navigation for tab switching** — it will make your views blank. Only use if you genuinely need pop-up overlays (modal dialogs).
|
|
|
|
```javascript
|
|
(async () => {
|
|
const ha = document.querySelector("home-assistant");
|
|
const conn = ha.hass.connection;
|
|
|
|
const cfg = await conn.sendMessagePromise({type: 'lovelace/config', url_path: 'dashboard-haus'});
|
|
|
|
for (const view of cfg.views) {
|
|
const cards = view.cards || [];
|
|
const popupIdx = cards.findIndex(c => c.card_type === 'pop-up');
|
|
if (popupIdx === -1) continue;
|
|
|
|
const popup = cards[popupIdx];
|
|
const navIdx = cards.findIndex(c => c.card_type === 'bottom-navigation');
|
|
|
|
// Content cards = everything EXCEPT pop-up and bottom-nav
|
|
const contentCards = cards.filter((c, i) => i !== popupIdx && i !== navIdx);
|
|
|
|
// Move content INTO the pop-up
|
|
popup.cards = contentCards;
|
|
|
|
// Rebuild: [pop-up (with content), bottom-nav]
|
|
const newCards = [popup];
|
|
if (navIdx !== -1) newCards.push(cards[navIdx]);
|
|
|
|
view.cards = newCards;
|
|
}
|
|
|
|
await conn.sendMessagePromise({
|
|
type: 'lovelace/config/save',
|
|
url_path: 'dashboard-haus',
|
|
config: cfg
|
|
});
|
|
})();
|
|
```
|
|
|
|
### Revert Script (Remove Pop-ups Entirely)
|
|
|
|
This is what actually fixed the blank-tab issue:
|
|
|
|
```javascript
|
|
(async () => {
|
|
const ha = document.querySelector("home-assistant");
|
|
const conn = ha.hass.connection;
|
|
|
|
const cfg = await conn.sendMessagePromise({type: 'lovelace/config', url_path: 'dashboard-haus'});
|
|
|
|
// Remove all pop-up cards from all views
|
|
for (const view of cfg.views) {
|
|
view.cards = (view.cards || []).filter(c => c.card_type !== 'pop-up');
|
|
}
|
|
|
|
await conn.sendMessagePromise({
|
|
type: 'lovelace/config/save',
|
|
url_path: 'dashboard-haus',
|
|
config: cfg
|
|
});
|
|
})();
|
|
```
|
|
|
|
### Verification
|
|
|
|
- Check `cfg.views[].cards` structure — no card should have `card_type: 'pop-up'` with nested `cards:` if using bottom-navigation
|
|
- Navigate to each view hash — content should be visible immediately
|
|
- 0 render errors in browser console
|
|
- **Test on a real browser, not just headless** — the headless browser may fail to render cards after `homeassistant.reload_all` + service worker clear, even when the config is correct
|
|
|
|
### Headless Browser Rendering Issue
|
|
|
|
After `homeassistant.reload_all` + clearing service workers/caches, the headless browser failed to render ANY dashboard (including the old Übersicht with 43 cards). `ha-card` count was 0 across all dashboards. The config was verified correct via WebSocket (correct card structure, entity IDs, no errors). This appears to be a headless-browser caching issue, not a config issue. Testing on a real browser/mobile device is the reliable verification method.
|