You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Also as a side-note I know you can use class:list directive which has clsx built in, but i just found it easiest to demonstrate this behaviour with styles so I just used this as it's from a real-life use-case for a low-code component library i'm authoring, since in my scenario I'm sometimes using more complex styling imports than just the base clsx for stuff like variants and whatnot.
The first instance of the component works fine and renders with the background as expected. However the second one with class="py-4 does not merge as expected, since the {...props} spread overrides the later defined class definition.
How to fix this (currently available workaround):
In order to fix this behaviour, we'll need to destructure the conflicting attributes i.e.
Had to rename class to className in the destructuring, since class is a reserved keyword in js.
Now in my page definition
---importWorkaroundfrom'@/components/Workaround.astro'---
<Workaround>this works</Workaround>
<Workaroundclass="py-4">this also works</Workaround>
This fixes the issue, where the classes merge succesfully with the bg-lime-300 and py-4 since we destructured the attribute class and the {...props} rest arg no longer overrides it.
Now we fixed the issue, but obviously this is very error prone if a developer introduces any further custom/explicit attribues in the future, they will also need to be explicitly destructured, otherwise they will be overriden. This is an error-prone behaviour in my opinion.
What's the expected result?
I would expected the attribute spread to be compiled / built correctly, respecting the order of the spread operator and it's attribute definitions, aligning the behaviour with other frameworks like react, solid, vue, etc.
This works out of the box, the {...props} do not override className definition, since the className definition takes precedence in definition order over the spread operator.
@samuelhulla Thank you for opening this issue! I have been meaning to report this since the very early days of Astro, but a combination of procrastination and low spoons means I've been working around it for literal years at this point 😅
I should note that a similar issue with likely the same root cause is that spread props do not override the explicit attributes that come before it. This pattern, when it works, can be useful when you want to set some default attribute values that should be overridden by spread props. (I use this pattern all the time in JSX)
<!-- `type` prop passed to the component should override `type="button"` -->
<buttontype="button" {...Astro.props}>
<slot />
</button>
Ah, so HTML doesn't work how I would expect here. Overridden props do come after previous ones, but because they all appear in the HTML, the browser actual uses the first value as the value, not the last, which is what I would expect. Here's a simpler example of what gets rendered: https://codepen.io/matthewp/pen/abggJgy
So fixing this will be a compiler change, unfortunately. I think what we'd have to do is if there is a spread in the attributes, move any static values into the spread function rather than treat them separately, as we currently do.
@matthewp I see. Kind of begs the question wether astro should adhere more closely to the native HTML behaviour or align it's behaviour more to the js-land of rendering frameworks.
I still think it's bit better to have it aligned more with the latter option, given a lot of Astro users do come from the React/Vue/Svelte/Solid land, but it's ultimately your call guys.
Astro Info
If this issue only occurs in one browser, which browser is a problem?
No response
Describe the Bug
With a super simple component definition
Now let's consider a simple page usage
The first instance of the component works fine and renders with the background as expected. However the second one with
class="py-4
does not merge as expected, since the{...props}
spread overrides the later definedclass
definition.How to fix this (currently available workaround):
In order to fix this behaviour, we'll need to destructure the conflicting attributes i.e.
Now in my page definition
This fixes the issue, where the classes merge succesfully with the
bg-lime-300
andpy-4
since we destructured the attributeclass
and the{...props}
rest arg no longer overrides it.Now we fixed the issue, but obviously this is very error prone if a developer introduces any further custom/explicit attribues in the future, they will also need to be explicitly destructured, otherwise they will be overriden. This is an error-prone behaviour in my opinion.
What's the expected result?
I would expected the attribute spread to be compiled / built correctly, respecting the order of the spread operator and it's attribute definitions, aligning the behaviour with other frameworks like react, solid, vue, etc.
This works out of the box, the
{...props}
do not overrideclassName
definition, since theclassName
definition takes precedence in definition order over the spread operator.Aligning with the same spread operator behaviour as in javascript objects, i.e.
Where if
obj
had a keyfoo
, it would be overriden with the value ofbar
, since the keyfoo
was manually defined after the spread operator happened.Link to Minimal Reproducible Example
https://stackblitz.com/edit/withastro-astro-uen4d4?file=src%2Fcomponents%2FBroken.astro
Participation
The text was updated successfully, but these errors were encountered: