softr-vibe-coding 1.6.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this skill are documented here. Versions follow [Semantic
4
4
 
5
5
  Entries from 1.3.1 onward are generated automatically from git commit subjects between version bumps (see `.github/workflows/publish.yml`). Entries before 1.3.1 were backfilled by hand from the existing commit history.
6
6
 
7
+ ## [1.8.0] - 2026-06-04
8
+ - Expand references/native-chrome-styling.md to the full native shell — add Footer (semantic <footer> target + 160px/overflow-wrap contact-column email-wrap fix), floating "island" header/footer treatment, and Page background (Softr stacks the same fill on html/body/#page-content/inner-wrapper, so paint on html + clear the stack, EXCLUDING the .softr-topbar subtree so the dropdown panel survives) + a Console background-finder snippet; broaden SKILL.md Reference Guides row + README; add anti-patterns row for the page-background stacking; bump to 1.8.0
9
+
10
+ ## [1.7.0] - 2026-06-04
11
+ - Add references/native-chrome-styling.md — restyle Softr's native header/top bar/nav/dropdowns via global Custom Code CSS (target stable .softr-* / ARIA-Radix selectors instead of regenerated f8f11e5_* hashes, the dropdown column-grid blank-space fix, icon/label color-inherit, restyle-vs-replace tradeoffs); add SKILL.md scope note + Reference Guides row; add two anti-patterns rows; update README; bump to 1.7.0
12
+
7
13
  ## [1.6.0] - 2026-06-03
8
14
  - Document useNavigationBlocker for form-dirty navigation guards in Softr SPA mode
9
15
 
package/README.md CHANGED
@@ -18,6 +18,7 @@ This Claude skill teaches Claude Code how to generate complete, polished Softr V
18
18
  - **All 14 Softr data sources** — Airtable, Softr Database, Google Sheets, HubSpot, Notion, Coda, monday.com, SmartSuite, ClickUp, Xano, Supabase, BigQuery, SQL Database, and REST API — each with field mapping, rate limits, and gotchas
19
19
  - **Helper blocks & cross-block patterns** — Invisible helper blocks for multi-table access via `window` globals + `CustomEvent`, `useWindowData` hook, breadcrumb navigation, saved views architecture
20
20
  - **Advanced integrations** — Shadow DOM CSS isolation for third-party libraries (Leaflet, Mapbox, TinyMCE, Quill, FullCalendar)
21
+ - **Native shell styling** — re-skin Softr's native top bar, **footer**, nav, dropdowns, and **page background** via global Custom Code CSS (stable selectors vs. hashed classes, floating "island" header/footer, the dropdown grid fix, the multi-layer page-background stacking, restyle-vs-replace) — distinct from blocks
21
22
  - **UI/UX design guidelines** — 26 sections covering visual hierarchy, color, typography, spacing, motion design, accessibility, responsive patterns, and an AI slop anti-pattern checklist
22
23
  - **Self-validation** — Claude checks for Softr bundler compatibility (no optional chaining, correct imports, container wrappers, `getFieldValue()` wrapping, hooks ordering) before delivering code
23
24
  - **Premium visual baseline** — Every block ships polished from v1: gradient backgrounds, card elevation, loading skeletons, empty states, error states
@@ -184,6 +185,10 @@ softr-vibe-coding/
184
185
  │ │ # install, scope limitations)
185
186
  │ ├── advanced-integrations.md # Shadow DOM CSS isolation (69 lines)
186
187
  │ │ # Leaflet, Mapbox, TinyMCE, Quill, FullCalendar
188
+ │ ├── native-chrome-styling.md # Restyle Softr's native shell (header, footer,
189
+ │ │ # nav, dropdowns, page background) via global
190
+ │ │ # Custom Code CSS — stable selectors, floating
191
+ │ │ # islands, dropdown grid fix, multi-layer page-bg
187
192
  │ ├── anti-patterns.md # Categorized violation catalog (86 lines)
188
193
  │ │ # Data access, mutations, hooks, layout,
189
194
  │ │ # permissions, helper blocks
package/SKILL.md CHANGED
@@ -20,6 +20,8 @@ allowed-tools: Read Write Glob Grep Bash
20
20
 
21
21
  You generate complete, production-ready Softr Vibe Coding blocks as JSX files. A Vibe Coding block is a JavaScript file with a default-exported React component that runs exclusively in the browser inside a Softr app.
22
22
 
23
+ > **Scope note — blocks vs. native chrome.** A block is page *content*, rendered inside a shadow DOM. Softr's global **header / top bar / nav / dropdown menus** are native chrome (configured in Studio, rendered in the main document) — you **cannot** build or replace them as a block. To restyle them, add CSS to Settings → Custom Code → Code inside header. See [references/native-chrome-styling.md](references/native-chrome-styling.md).
24
+
23
25
  ## Your Workflow
24
26
 
25
27
  1. **Detect the brand source (always run first, before any block work).** Check if a `./DESIGN.md` file exists in the project folder you're about to work in.
@@ -155,6 +157,7 @@ For advanced patterns beyond data fetching, load the relevant reference when the
155
157
  | Small reusable patterns — `localStorage` cross-page state, clipboard copy button | [references/common-patterns.md](references/common-patterns.md) |
156
158
  | Writing Airtable Automation Scripts / Scripting Extension scripts / Airtable formulas — companion to Softr blocks for cross-table cascades and computed values | [references/airtable-automations.md](references/airtable-automations.md) |
157
159
  | AI-assisted Softr DB schema discovery / field-ID lookup / record reads via the official Softr MCP server (sibling to the in-block `useRecords` workflow) | [references/softr-database-mcp.md](references/softr-database-mcp.md) |
160
+ | Restyling Softr's **native shell — header / footer / nav / dropdowns / page background** (not a block; it's Softr chrome, done with global Custom Code CSS): stable selectors vs. hashed classes, floating "island" header+footer, the dropdown blank-space grid fix, the multi-layer page-background stacking, restyle-vs-replace | [references/native-chrome-styling.md](references/native-chrome-styling.md) |
158
161
 
159
162
  ## Code Structure
160
163
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "softr-vibe-coding",
3
- "version": "1.6.0",
3
+ "version": "1.8.0",
4
4
  "description": "Claude Code skill for generating production-ready Softr Vibe Coding blocks (JSX). Installs into ~/.claude/skills/ and auto-updates on each Claude Code session.",
5
5
  "bin": {
6
6
  "softr-vibe-coding": "./bin/cli.js"
@@ -63,6 +63,9 @@ Run through this catalog before delivering any block. Every row is a violation o
63
63
  | Painting `backgroundColor: BRAND_CANVAS` on a Vibe Coding block's outer wrapper when `custom-code-header.html` already sets `body { background-color: var(--brand-canvas) !important }` | Don't double-paint. If the body bg is already the brand canvas, the block leaves its own backgroundColor unset and the page bg shows through. Painting the same color twice produces a visible seam — Softr's content wrapper sits between `<body>` and the Vibe Coding block, and the two backgrounds composite slightly differently due to sub-pixel rendering, transparency stacking, or wrapper paddings. Set fontFamily and color on the block's wrapper (those don't inherit cleanly through shadow DOM), but **leave backgroundColor unset** — let the page bg flow through. The exception: if the block needs a brand-tinted *section* (e.g., a card-style admin shell that's different from the page bg), paint that bg explicitly on its specific container, not on the outer wrapper. |
64
64
  | `document.getElementById(...)` / `document.querySelector(...)` to find an element inside the block — for example, a hidden `<input type="file">` triggered by a visible "Upload" button via `getElementById('myInput').click()` | Vibe Coding blocks render inside a shadow DOM. The global `document` traversal stops at the shadow boundary, so id/selector lookups for elements inside the block return `null`. The user-visible symptom is a control that does nothing — no error, no file picker, no focus, no scroll — because the chained `.click()` / `.focus()` / `.scrollIntoView()` was called on `null`. Use a **React `useRef`** instead: `var inputRef = useRef(null)`, then `<input ref={inputRef} />` and `<button onClick={function() { if (inputRef.current) inputRef.current.click(); }}>`. Refs hold direct node references and don't depend on DOM traversal, so they work regardless of which DOM tree the node lives in. This applies to every "trigger a hidden element" pattern: hidden file inputs, programmatic focus, scroll-into-view, `.click()` on a non-visible button. |
65
65
  | Using `window.addEventListener("beforeunload", ...)` as the only unsaved-changes guard in a form block | Softr is a SPA. Internal nav (Softr's nav bar, sidebar links, `<NavigationAction>`) changes the route via the client-side router — `beforeunload` only fires on full page unload (tab close, refresh, external link), so the warning silently misses every in-app navigation. Use `useNavigationBlocker(isDirty)` from `@/lib/use-navigation-blocker` instead; it covers SPA nav AND browser unload with one API. Softr's Vibe Coding bundler often wires this automatically when a form is detected as dirty — you only need to add it manually for advanced cases (multi-step forms, custom dirty tracking, blocking on non-form state). See [common-patterns.md](common-patterns.md#navigation-blocker-for-unsaved-changes). |
66
+ | Targeting Softr's hashed build classes (e.g. `.f8f11e5_m9ntthp`) when restyling the native header/nav from `custom-code-header.html` | Softr regenerates the hash on every deploy, so the rule silently dies. Target stable hooks: `.softr-topbar`, `.softr-nav-link`, `.softr-nav-button`, `.softr-nav-logo`, `#topbar-root`; for dropdown menus (no `softr-*` class) use the Radix/ARIA attrs `[role="menu"]` / `[role="menuitem"]` / `[role="group"]` / `[aria-expanded="true"]`, scoped under `.softr-topbar`. The native header is Softr chrome (main document), not a block — it can't be built as a Vibe Coding block. See [native-chrome-styling.md](native-chrome-styling.md). |
67
+ | Softr nav dropdown panel shows a tall blank gap below the items, and `height: auto` won't shrink it | The items sit in a CSS grid Softr sets to `grid-auto-flow: column` with pre-sized empty row tracks (`grid-template-rows: 60px 60px…`). Override the flow on `.softr-topbar [role="menu"] [role="group"]`: `grid-auto-flow: row !important; grid-template-rows: none !important; grid-auto-rows: auto !important` (leave `grid-template-columns` to preserve the menu width). Verified June 2026. See [native-chrome-styling.md](native-chrome-styling.md). |
68
+ | Setting the page background on `body` (or any single element) — it appears to do nothing | Softr paints the SAME page fill on `html`, `body`, `#page-content`, AND a deeper class-less wrapper div, stacked — so styling one gets covered. Paint your backdrop on `html`, then clear the duplicates above it: `body`, `#page-content`, and `#page-content div` — but EXCLUDE the header subtree with `:not(.softr-topbar):not(.softr-topbar *)` (it renders inside `#page-content`, and `#page-content`'s id specificity would otherwise flatten the dropdown panel). Verified June 2026. See [native-chrome-styling.md](native-chrome-styling.md). |
66
69
 
67
70
  ## Permissions
68
71
 
@@ -0,0 +1,219 @@
1
+ # Styling Softr's Native Shell (Header · Footer · Page Background) via Custom Code
2
+
3
+ **This is NOT about Vibe Coding blocks.** Softr's top bar, navigation, dropdown menus, footer, and the page background are part of the *native app shell* — configured in Softr Studio and rendered in the **main document**, not inside a block's shadow DOM. You **cannot** build or replace them as a Vibe Coding block. To re-skin them, add **CSS to Settings → Custom Code → Code inside header** (the same place brand fonts/tokens live, i.e. the `custom-code-header.html` produced by `building-design-md`). Pure CSS — no markup, no JS — and the native chrome stays in place, so Softr's auth-aware nav (account menu, sign-out, user-group gating) keeps working.
4
+
5
+ This doc covers the **header / nav / dropdowns**, the **footer**, the **floating "island" treatment** for both, and the **page background** — which is trickier than it looks, because Softr stacks the same fill on several layers.
6
+
7
+ > **Mirror of the block rule.** Global `custom-code-header.html` CSS reaches native chrome (main document) but **not** blocks (shadow DOM). Inside a block you apply brand styles inline; for native chrome you apply them with this global CSS. (See [anti-patterns.md](anti-patterns.md) for the block side.)
8
+
9
+ ## Selector discipline — the #1 rule
10
+
11
+ Softr's rendered markup carries two kinds of classes:
12
+
13
+ - **Hashed build classes** like `f8f11e5_m9ntthp` — **NEVER target these.** Softr regenerates the hash on every deploy, so your rules silently die.
14
+ - **Stable hooks** — target these instead:
15
+
16
+ | Element | Stable selector |
17
+ |---|---|
18
+ | Sticky root wrapper | `#topbar-root` |
19
+ | The bar itself | `.softr-topbar` (also `[data-testid="topbar"]`) |
20
+ | Logo image | `.softr-nav-logo` |
21
+ | Nav links (Home, etc.) | `.softr-nav-link` |
22
+ | Nav buttons / dropdown triggers | `.softr-nav-button` |
23
+ | Overflow "…" trigger | `.softr-nav-category` |
24
+ | Active / current link | `.softr-nav-link[data-active="true"]` |
25
+ | Open dropdown trigger | `.softr-nav-button[aria-expanded="true"]` |
26
+
27
+ **Dropdown menus have NO `softr-*` class** — they're **Radix UI**, so target ARIA / Radix attributes (stable across deploys):
28
+
29
+ | Element | Stable selector |
30
+ |---|---|
31
+ | Menubar (the row of items) | `[role="menubar"]` |
32
+ | Open dropdown panel | `[role="menu"]` (+ `[data-state="open"]`, `[data-side="bottom"]`) |
33
+ | A menu item | `[role="menuitem"]` |
34
+ | Items group inside the panel | `[role="group"]` |
35
+ | Keyboard-highlighted item | `[role="menuitem"][data-highlighted]` |
36
+
37
+ Scope dropdown rules under `.softr-topbar` (Softr renders the header menu *inside* the nav) so they don't bleed into other Radix menus elsewhere in the app. Use `!important` + the `.softr-topbar` scope to beat Softr's own class rules.
38
+
39
+ ## Recipe: restyle the top bar
40
+
41
+ ```css
42
+ /* Bar surface */
43
+ .softr-topbar {
44
+ background-color: #02006C !important; /* your brand deep color */
45
+ border-bottom: 1px solid #1E1666 !important;
46
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25) !important;
47
+ }
48
+
49
+ /* Nav items: brand font, pill, your text color */
50
+ .softr-topbar .softr-nav-link,
51
+ .softr-topbar .softr-nav-button {
52
+ font-family: var(--brand-font-display) !important;
53
+ color: #FFFFFF !important;
54
+ border-radius: 9999px !important;
55
+ }
56
+
57
+ /* Icons (currentColor SVGs) + labels carry their OWN color — force them to follow the link.
58
+ Without this, labels render in Softr's default muted grey even after you set `color`. */
59
+ .softr-topbar .softr-nav-link *,
60
+ .softr-topbar .softr-nav-button * { color: inherit !important; }
61
+
62
+ /* Spacing — pills can end up touching; margin works regardless of the menubar's display type */
63
+ .softr-topbar [role="menubar"] .softr-nav-link,
64
+ .softr-topbar [role="menubar"] .softr-nav-button { margin: 0 4px !important; }
65
+
66
+ /* Single out ONE item as a CTA by its href (the only stable way to target one nav item) */
67
+ .softr-topbar .softr-nav-link[href*="your-form-host"] {
68
+ background: #9B23D0 !important;
69
+ color: #FFFFFF !important;
70
+ box-shadow: var(--brand-shadow-cta-glow) !important;
71
+ }
72
+ ```
73
+
74
+ ### Gotchas (verified June 2026)
75
+
76
+ - **Nav font defaults to Inter.** Your brand `@font-face`/`<link>` loads globally, but the bar's `font-family` is set on Softr's classes — you must target `.softr-nav-link` / `.softr-nav-button` to change it.
77
+ - **Icon + label color** comes from Softr's classes, so a plain `color:` on the link often doesn't take — use the `* { color: inherit !important }` trick above (SVGs use `currentColor`, so they follow too).
78
+ - **Custom code renders on the PUBLISHED app only — not in the Studio editor.** The header looks unchanged in the builder; always verify on the live app.
79
+ - **Account avatar on a dark bar:** Softr's logged-in account button can blend into a dark bar — give it a contrasting ring if you darken the surface.
80
+
81
+ ## Gotcha: dropdown panel has a tall blank gap below the items
82
+
83
+ Softr lays dropdown items in a **CSS grid** with `grid-auto-flow: column` and a **fixed set of pre-sized row tracks** (`grid-template-rows: 60px 60px 60px…`). With only 2–3 items the extra rows stay empty → a tall panel with dead space. **`height: auto` does NOT fix it** — the grid template defines those tracks. Override the flow instead:
84
+
85
+ ```css
86
+ .softr-topbar [role="menu"],
87
+ .softr-topbar [role="menu"] > div,
88
+ .softr-topbar [role="menu"] [role="group"] {
89
+ height: auto !important;
90
+ min-height: 0 !important;
91
+ grid-auto-flow: row !important; /* one item per row */
92
+ grid-template-rows: none !important; /* drop the reserved empty tracks */
93
+ grid-auto-rows: auto !important;
94
+ }
95
+ /* leave grid-template-columns alone — it sets the menu width */
96
+ ```
97
+
98
+ Center each item's text and drop the empty description slot Softr reserves:
99
+
100
+ ```css
101
+ .softr-topbar [role="menu"] [role="menuitem"] { display: flex !important; align-items: center !important; }
102
+ .softr-topbar [role="menu"] [role="menuitem"] div:empty { display: none !important; }
103
+ ```
104
+
105
+ ## Floating "island" header
106
+
107
+ To turn a full-bleed bar into a floating, rounded "island" (inset from the edges): make the sticky root + Softr's Studio wrappers transparent so only the bar paints, then constrain + round + shadow the bar itself.
108
+
109
+ ```css
110
+ /* The sticky root and its Studio wrappers paint full-width — clear them so only the
111
+ bar shows, floating over the page. */
112
+ #topbar-root,
113
+ #topbar-root > div,
114
+ #topbar-root > div > div { background: transparent !important; }
115
+
116
+ #topbar-root { padding: 24px 16px 0 !important; } /* gap above + at the sides */
117
+
118
+ .softr-topbar {
119
+ max-width: 1200px !important;
120
+ margin: 0 auto !important; /* center the island */
121
+ border-radius: 22px !important;
122
+ box-shadow: 0 12px 30px rgba(0, 0, 0, 0.28) !important;
123
+ }
124
+
125
+ /* Optional: group the nav cluster toward the right-of-center */
126
+ .softr-topbar [role="menubar"] { justify-content: flex-end !important; }
127
+ ```
128
+
129
+ ## Footer
130
+
131
+ **The native footer has NO `softr-*` class — only `f8f11e5_*` hashes.** Target the semantic **`<footer>`** element instead. Safe: Vibe Coding blocks are shadow-DOM isolated, so `footer { … }` reaches only Softr's native footer, never a block.
132
+
133
+ ```css
134
+ footer {
135
+ max-width: 1200px !important;
136
+ margin: 24px auto !important; /* inset → elevated "island" card */
137
+ border-radius: 22px !important;
138
+ background-color: #02006C !important; /* e.g. navy, to match a navy header island */
139
+ color: #FFFFFF !important;
140
+ box-shadow: 0 14px 34px rgba(0, 0, 0, 0.18) !important;
141
+ }
142
+ footer * { color: inherit !important; } /* recolor all footer text/links white in one shot */
143
+ ```
144
+
145
+ **Footer contact column wraps the email mid-word.** Softr pins that column to a fixed `width: 160px` with `overflow-wrap: break-word`, so a long email splits across lines. Fix by no-wrapping the links (target by their stable `tel:` / `mailto:` href) and letting the column grow to content:
146
+
147
+ ```css
148
+ footer a[href^="tel:"],
149
+ footer a[href^="mailto:"] { white-space: nowrap !important; }
150
+ footer [role="list"],
151
+ footer [role="list"] > div,
152
+ footer [role="list"] > div > div {
153
+ width: auto !important;
154
+ min-width: max-content !important;
155
+ max-width: none !important;
156
+ }
157
+ ```
158
+
159
+ ## Page background
160
+
161
+ **The trickiest one — Softr paints the SAME fill on FOUR stacked layers:** `html`, `body`, `#page-content` (stable id; classes `content spr-content-root`), AND a deeper **class-less wrapper div** nested a few levels inside `#page-content`. Style any one layer and the ones above cover it — this is why setting `body` alone appears to "do nothing."
162
+
163
+ **Pattern: paint the backdrop on the bottom layer (`html`), then clear the duplicate fills off everything stacked above it.**
164
+
165
+ ```css
166
+ /* 1. Paint the backdrop on the bottom layer. A layered "combo" reads premium:
167
+ soft glow + faint dot-grid + base gradient. background-image order = top→bottom. */
168
+ html {
169
+ background-color: #F0F3FC !important; /* fallback base */
170
+ background-image:
171
+ radial-gradient(75rem 42rem at 50% -12%, rgba(155, 35, 208, 0.08), transparent 60%), /* glow */
172
+ radial-gradient(rgba(2, 0, 108, 0.045) 1px, transparent 1.6px), /* dot-grid */
173
+ linear-gradient(180deg, #E7EAFB 0%, #F2F4FD 45%, #FAFBFF 100%) !important; /* gradient */
174
+ background-size: 100% 100%, 24px 24px, 100% 100% !important;
175
+ background-repeat: no-repeat, repeat, no-repeat !important;
176
+ background-attachment: fixed !important; /* calm while content scrolls */
177
+ }
178
+
179
+ /* 2. Clear the duplicate fills stacked above <html> so the backdrop shows through —
180
+ but EXCLUDE the header subtree (see gotcha). The inner content wrapper is
181
+ class-less and nested deep, so clear ALL divs inside #page-content. */
182
+ body,
183
+ #page-content { background-color: transparent !important; background-image: none !important; }
184
+ #page-content div:not(.softr-topbar):not(.softr-topbar *) {
185
+ background-color: transparent !important;
186
+ background-image: none !important;
187
+ }
188
+ ```
189
+
190
+ **Gotcha — don't clear the header into oblivion.** The header (`#topbar-root` → `.softr-topbar`, *including its dropdown panel*) renders **inside** `#page-content`, so a blanket `#page-content div { background: transparent }` flattens the dropdown's white panel too. And `#page-content`'s **id specificity (1,0,1) out-specifies** class/attr rules like `.softr-topbar [role="menu"]` (0,2,0) — so the clear wins silently and your earlier menu styling vanishes. Always exclude the header subtree: `:not(.softr-topbar):not(.softr-topbar *)`. (Cards are shadow-DOM blocks → their backgrounds are untouched; the footer is a `<footer>`, not a div → safe.)
191
+
192
+ ## Finding the element to target
193
+
194
+ **Transient menus** (close on blur) — DevTools can't right-click them. Freeze: in the Console run `setTimeout(function () { debugger; }, 4000)`, open the menu within 4s, then — paused — element-pick the panel and read the **Computed** tab. Resume with the ▶ button. ("Emulate a focused page" in the Elements `:hov` menu is a lighter alternative.)
195
+
196
+ **Which element paints a background** — the element-picker keeps grabbing a *transparent* overlay sitting on top, so scan instead. Paste this in the Console; it lists `html`, `body`, and every large element with a real background color (tag / id / class / color / size), so you can spot the actual painter and its stable hook:
197
+
198
+ ```js
199
+ (function () {
200
+ var hits = [];
201
+ var all = document.querySelectorAll('html, body, body *');
202
+ for (var i = 0; i < all.length; i++) {
203
+ var el = all[i], bg = getComputedStyle(el).backgroundColor, r = el.getBoundingClientRect();
204
+ if (bg !== 'rgba(0, 0, 0, 0)' && bg !== 'transparent' &&
205
+ (el === document.documentElement || el === document.body || (r.width > 1200 && r.height > 400))) {
206
+ hits.push({ tag: el.tagName.toLowerCase(), id: el.id || '',
207
+ cls: (typeof el.className === 'string' ? el.className : ''),
208
+ bg: bg, size: Math.round(r.width) + 'x' + Math.round(r.height) });
209
+ }
210
+ }
211
+ console.table(hits);
212
+ })();
213
+ ```
214
+
215
+ ## Restyle vs. replace
216
+
217
+ **Restyle the native bar (recommended):** robust, global, keeps Softr's auth-aware nav (account menu, user-group-gated items) and stays editable in Studio.
218
+
219
+ **Replace it** (hide `#topbar-root`, inject a fully custom HTML/JS header globally): only if you need structure the native nav can't do — e.g. multi-column mega-menus with icon cards. It's **fragile**: you lose Softr's logged-in account menu + user-group gating, you must re-init the JS on every SPA route change (Softr swaps pages without a full reload), and the custom header won't render in the Studio editor. Steer users to restyle unless the structure genuinely requires replacement.