Skip to content

lego request: esa-app-shell — four defects (dead bar border, inert accent, no full-height rail, raw omnibox icon) #28

Description

@newspaceracer

Filed from firma2-design (ProjectFirma 2.0 spoke) · 2026-08-19
Found while composing the spoke's first prototype (/prototypes/projects) inside esa-app-shell.

Four independent defects in one component. Each verified against hub source and in a headless browser.


1. The bar's border-bottom rule never applies (Astro scoping)

esa-app-shell.astro declares:

.esa-app-shell__bar { flex: none; border-bottom: var(--border-width-default, 1px) solid var(--color-border-default-strong, #bbbbbb); }

It never matches. The shell renders <EsaAppBar tone="surface" as="header" class="esa-app-shell__bar">, and because EsaAppBar is a child .astro component its root <header> carries esa-app-bar's own scope id (data-astro-cid-ahjxwpid), not the shell's (data-astro-cid-za3k4dj5). The scoped selector selects nothing.

Verified in-browser — the tokens resolve fine, the rule simply doesn't land:

--border-width-default        -> 1px
--color-border-default-strong -> #b9bcb8
header computed border-bottom -> 0px none      ← rule never applied

Why it matters: the bar has no fill to fall back on. Hub defaults set --color-background-elevation-raised (what esa-app-bar paints) to var(--color-gray-1) — the same value as --color-background-default, the canvas. The border is the only thing separating app chrome from page, so the bar renders invisibly.

Probably affects any other rule the shell writes against a child component's root, not just this one — worth auditing together.

Note for whoever fixes it: re-pointing --color-background-elevation-raised so the bar gets its own value is not a viable spoke-side workaround. It drops two dataviz swatches below their contrast floor — check-themes.mjs goes 66/66 → 2 FAIL (dataviz-categorical-8 2.93:1, needs 3:1; dataviz-sequential-1 1.96:1, needs 2:1). That role carries dataviz backgrounds too, so it isn't free to move.

2. .esa-app-shell--accent {} is an empty stub

The accent prop is documented in the component header as adding "a faint brand-TINTED neutral wash to the bar (a color-mix, not a fill)". It is wired to .esa-app-shell--accent — which has no declarations. Passing accent does nothing.

This would have been the sanctioned fix for #1's invisible bar.

3. No full-height-sidenav layout variant

The shell hard-codes one arrangement: full-width bar stacked above a row containing the rail. The common alternative — rail owning full viewport height with the bar beside it — has no prop.

Working around it from a spoke means reaching into the shell's internals, because the nav is a grandchild (.esa-app-shell > .esa-app-shell__body > esa-sidebar-nav) and can't be placed by a grid on the shell:

.esa-app-shell       { display: grid; grid-template-columns: auto minmax(0,1fr); grid-template-rows: auto minmax(0,1fr); }
.esa-app-shell__body { display: contents; }   /* dissolve the wrapper */
.esa-app-shell__nav  { grid-column: 1; grid-row: 1 / 3; }
.esa-app-shell__bar  { grid-column: 2; grid-row: 1; }
.esa-app-shell__content { grid-column: 2; grid-row: 2; min-height: 0; }

A layout="rail-full-height" prop (or similar) would stop spokes needing to know that DOM shape.

4. The omnibox trigger's icon is a raw literal, off the icon ramp

Already filed as #27 — folded in here only so this list is complete. See that issue.


Workarounds currently shipping in firma2-design

All in src/layouts/AppLayout.astro, each commented as temporary and pointing here:

Related

The same prototype surfaced a separate tokens-architecture gap (no tier-1 control-size ramp, so --sidenav-item-height and friends are raw px): #29

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions