Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

finding(plugin-dashboard): MetricWidgetProps / MetricCardProps declare no DOM passthrough, so the id / role / aria-* the spread accepts at runtime are a type error for a TS consumer #4426

Closed

Description

@yinlianghui

Observation-class finding, measured while implementing #4357. Pre-existing on origin/main and unchanged by that PR; filed rather than widened into it, because closing it changes the exported props interface of two components.

What happens

Both components end their prop list with a ...props spread onto the Shadcn Card. #4357 keeps the spread deliberately — it is the components' genuine DOM/aria passthrough, and removing it would delete the only way a host can put id, role or an aria-* on a KPI card. But neither MetricWidgetProps nor MetricCardProps extends React.HTMLAttributes, and neither declares those keys, so what the runtime accepts the type refuses.

Measured against the built dist/index.d.ts from a consumer package:

probe.tsx(23,52): error TS2322: Type '{ label: string; value: number; id: string; role: string; "aria-label": string; }'
  is not assignable to type 'IntrinsicAttributes & MetricWidgetProps & SchemaHostProps'.

The same source compiles and behaves correctly at runtime — the attributes reach the card. A JS consumer, or any SDUI author going through SchemaRenderer (which is untyped at that boundary), gets the passthrough; a TypeScript consumer importing the component directly cannot use it without a cast.

Why it is worth writing down even though nobody is blocked

It is the mirror image of #4357. That issue was renderer metadata reaching the DOM because the spread is open; this is DOM attributes being unreachable because the type is closed. Both come from the same unstated question — what may a dashboard widget legitimately receive? — and answering it once, in the type, is what makes "declared = enforced" true here in both directions instead of one.

Fix shape

Declare the passthrough: extend the interfaces with the subset of React.HTMLAttributes a KPI card should accept, or an explicit block mirroring what FieldWidgetDomProps does for field widgets (objectui#3221). Either way it widens the exported props interface, which by this repo's grading is a minor with the semantics in the changeset body (the objectui#4403 precedent), so it is not a drive-by rider on a patch fix. It should also be decided together with #4425 — if plugin widgets move to a toDomProps-style whitelist, the declared DOM set is exactly that whitelist and the two are one change.

No pm:queue — nothing a user hits today.


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 12, 2026
  2. yinlianghui commented on Aug 12, 2026

    @yinlianghui
    ContributorAuthor

    CLAIM + RULING — PM seat session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4426-metric-props-passthrough, one dev agent, one PR, Fixes #4426.

    Ruling (delegated, veto window open): declare the DOM passthrough the spread actually accepts — widen MetricWidgetProps/MetricCardProps so id/role/aria-label/data-* (what the #4428 measurement kept flowing) type-check for direct consumers, per whatever shape the card's own analysis proposes (measure the repo's convention for DOM-passthrough prop typing — e.g. extending the appropriate React.HTMLAttributes subset — and follow it; no invented third spelling). Minor changeset per the #4403 precedent (exported interface widens), never major. Zero runtime change; the #4428 pins pass untouched.

    Dispatch gate: branch after PR #4428 (same components) is in origin/main — poll.


    Generated by Claude Code

  3. added a commit that references this issue on Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions