# The consumer's current workarounds, what they look like, why they're fragile

Two real consumers, adiav2's `admin-portal-fe` and `factory-dashboard`, SSR AdiaUI
via Astro 5 + `custom-elements-ssr` (linkedom). Each open issue names a workaround
they currently maintain in their OWN app code (not in this framework). Knowing the
shape of each matters for two reasons: (1) it tells you what "done" looks like, the
workaround should become deletable once the underlying gh issue closes; (2) it's the
concrete evidence for WHY each open issue matters, beyond the abstract description.

## The ~110-line browser-API shim (gh#285, now deletable, unconfirmed)

Before every component module import, the consumer's SSR entry point ran a
prototype-patching shim: stubbed `attachInternals`, defined four no-op Observer
classes (`ResizeObserver`/`IntersectionObserver`/`MutationObserver`/`PerformanceObserver`),
and force-assigned `document.adoptedStyleSheets = []`. Two named fragilities:
- **Fragile import order**, the shim MUST execute before any component module
  loads, or the "deep-render pass" crashes anyway. This already broke once in a
  production bundle (per the issue), a bundler/tree-shaking change that reordered
  imports silently reintroduced the crash.
- **A global patch, not scoped**, patching `HTMLElement.prototype` /
  `globalThis.ResizeObserver` affects EVERY component and every other library in the
  same process, not just AdiaUI's.

**Status as of gh#285's fix (PR #292, merged 2026-07-17): the AdiaUI-facing sections
of this shim are no longer necessary**, the framework guards its own call sites now.
**Consumer-confirmed 2026-08-17 (gh#1430 §Additional context, against 0.8.40):**
`attachInternals`, the four Observer stubs and `adoptedStyleSheets` are all confirmed
unnecessary. **But gh#285's closing comment over-reached** in saying the shim "as a
whole" can go: two of its sections patch `CustomElementRender.prototype`, a
`setAttribute` null-guard and a `renderShadow` null-guard, i.e. they patch
`custom-elements-ssr` itself, which reads `shadowRoot.innerHTML` unconditionally and
AdiaUI is light-DOM-only, so `shadowRoot` is always `null`. Remove those two and every
SSR'd fixture dies with `Cannot read properties of null (reading 'innerHTML')`. No fix
in this repo can retire them; they belong to the renderer. Tell the next consumer that
explicitly rather than "the shim is unnecessary". (Also from that trial: `matchMedia`
was a further AdiaUI-side gap the #292 sweep missed, fixed by gh#1430, so a
`matchMedia` stub is not needed either from the version carrying it.)

## Attribute-only SSR registration restriction (gh#284, likely no longer necessary, unconfirmed)

The consumer restricts server-side custom-element registration to components whose
visible content derives ENTIRELY from attributes, `button-ui text="…"`, `icon-ui
name="…"`. Every container (`admin-shell`, `admin-sidebar`, `nav-ui`) and every
projected-text component (`text-ui`, `avatar-ui`, `badge-ui`, and by extension
anything using `<component>slotted text</component>` markup) must register
CLIENT-side only, upgrading after first paint.

**Status as of gh#284's narrowing (2026-07-17): the STAMP() reason for this
restriction is gone**, every component it names (and every other shipped
component with real content) currently derives its visible content from
properties/attributes only, never from light-DOM children, so `stamp()`'s
destructive replace never fires against real content for any of them (see
[`failure-shapes.md`](failure-shapes.md) §2 for the empirical survey). This did
NOT ship as a `stamp()` fix, it's a narrowing based on the CURRENT shape of the
component set, backed by a forward static audit
(`scripts/dev/audit-template-child-conflict.mjs`) that would catch a future
regression.

**UPDATE 2026-07-18, but there WAS a second, independent, real reason this
restriction was justified, now also fixed.** Every component this restriction
names is attribute/property-driven, and until PR #309, attribute-driven
content was ITSELF broken under a late/SSR upgrade (see `failure-shapes.md` §2's
"UPDATE 2026-07-18" and `guard-patterns.md` §2b): `attributeChangedCallback`
never replayed for pre-existing attributes on upgrade, so `<nav-item-ui
text="Profile">` rendered with an empty label regardless of the stamp()
question. That's now fixed at the framework level (`element.js`
`connectedCallback`). So as of the version carrying PR #309, both reasons this
restriction existed are addressed, not just the one gh#284 originally named.

As with gh#285's shim: don't assume the consumer has actually
relaxed this restriction without checking the issue thread for their confirmation, a consumer removing their own workaround is their change, not something this
narrowing does automatically. If the consumer's linkedom/`custom-elements-ssr`
setup surfaces something this repo's own repro didn't (a real second-connect
timing difference, an app-level component not covered by this framework), that's
new information worth feeding back into the issue, not something to assume away.

## gh#288 (property-only components), CLOSED 2026-07-18, workaround droppable

The consumer's PRE-fix behavior for `table-ui`/`chart-ui`/`select-ui` with
programmatic content was: render empty in the SSR response, then a per-page
wiring script does `customElements.whenDefined(...) → getElementById → assign
properties` after hydration. As of the fix, that boilerplate is droppable for all
three, `select-ui` via native `<option>` children (already worked, pre-existing),
`chart-ui` via a `data="[…]"` JSON attribute (already worked, pre-existing),
`table-ui` via the same `data="[…]"` attribute (new) plus `<col-def>` children for
columns (pre-existing). Don't assume the consumer has removed the wiring script
without their confirmation, see [`failure-shapes.md`](failure-shapes.md) §4 for
the full narrative.
