Skip to content

fix(react): skip undefined props in attachProps (v9) - #31349

Closed
ptmkenny wants to merge 1 commit into
ionic-team:major-9.0from
ptmkenny:react-attach-props-undefined-major-9
Closed

fix(react): skip undefined props in attachProps (v9)#31349
ptmkenny wants to merge 1 commit into
ionic-team:major-9.0from
ptmkenny:react-attach-props-undefined-major-9

Conversation

@ptmkenny

Copy link
Copy Markdown
Contributor

Issue number: resolves #31344

This is the v9 version of the PR #31345

@ptmkenny
ptmkenny requested a review from a team as a code owner August 12, 2026 16:01
@ptmkenny
ptmkenny requested a review from BenOsodrac August 12, 2026 16:01
@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

@ptmkenny is attempting to deploy a commit to the Ionic Team on Vercel.

A member of the Team first needs to authorize it.

@ShaneK

ShaneK commented Aug 15, 2026

Copy link
Copy Markdown
Member

Hey @ptmkenny! Sorry to do this twice, but I'm closing this one too and going with a different approach in #31361

Skipping the assignment for nullish values changes what undefined means for a prop that has a default. Right now <IonModal backdropDismiss={maybeUndefined} /> writes undefined over the @Prop() default of true, so with the assignment skipped the backdrop would start dismissing when it didn't before. It would also leave the generated components behaving differently, since those go through @lit/react, which assigns and then removes the attribute.

The new one mirrors @lit/react instead, and it has the tests you asked for. Thanks for the reproduction, it made this a lot easier to work through.

@ShaneK ShaneK closed this Aug 15, 2026
ShaneK added a commit that referenced this pull request Aug 17, 2026
Issue number: resolves #31344

---------

## What is the current behavior?

Currently, `attachProps` assigns every prop onto the element without
checking whether it has a value. Assigning a nullish value to a
reflected property stringifies it, so an unset optional prop lands as
`id="undefined"` and every element rendered that way shares an id.
Setting the prop back to `undefined` overwrites the attribute rather
than removing it. The same goes for `title`, `slot`, `lang`, and `dir`.

## What is the new behavior?

We now remove the attribute after assigning, when the value was nullish
and the name is a native property. That is what `@lit/react` already
does in its `setProperty`, so the hand-rolled wrappers and the generated
components behave the same way.

## Does this introduce a breaking change?

- [ ] Yes
- [X] No

In fact, this version of this fix was made explicitly to avoid
introducing more breaking changes at this time.

## Other information

This replaces #31349, which fixed the same issue by skipping the
property assignment for nullish values rather than removing the
attribute afterwards. That changes what `undefined` means for a prop
with a declared default. Today `<IonModal
backdropDismiss={maybeUndefined} />` writes `undefined` over the
`@Prop()` default of `true` so the backdrop doesn't dismiss, but with
the assignment skipped the default survives and it starts dismissing.
Same for `animated`, `showBackdrop`, and `keyboardClose`. It would also
leave the package inconsistent, because the generated components go
through `@lit/react`, which does assign, so `IonInput` and `IonButton`
would disagree about what `undefined` means. Mirroring `@lit/react`
avoids both, and this PR needs no BREAKING.md entry because of it.

Note that the repro in #31344 uses `IonToggle`, which is generated on v9
and already passes there. This covers the hand-rolled wrappers
`@lit/react` doesn't touch: the overlays, the routing proxies, and
`IonApp`/`IonIcon`/`IonNav`/`IonRouterOutlet`/the tabs components.

A prop removed from the JSX entirely, rather than set to `undefined`,
still isn't cleared, since `attachProps` only iterates the new props.
That's pre-existing and I left it alone, because three call sites pass a
filtered `newProps` against the full `prevProps` so the fix isn't as
simple as it would appear.

Co-authored-by: Patrick Kenny github@ptmkenny.com

## Current dev build:
```
8.8.19-dev.11786832241.150538c7
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

package: react @ionic/react package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants