Animate motion.meta attributes#3705
Conversation
When animating values on a <motion.meta> element (e.g. `content` on a theme-color meta tag), apply animated values as attributes rather than inline styles. Meta tags are not visually rendered, so the existing style-only render path produced no observable update. Fixes #3100 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Greptile SummaryThis PR fixes animating values on
Confidence Score: 4/5Safe to merge for the targeted use case; the change is small and well-tested, with no impact on any non-META element. The fix correctly addresses
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[renderHTML called] --> B{element.tagName === 'META'?}
B -- Yes --> C[renderAsAttrs = true]
B -- No --> D[renderAsAttrs = false]
C --> E[for key in style]
D --> E
E --> F{renderAsAttrs?}
F -- Yes --> G[element.setAttribute key, value]
F -- No --> H[elementStyle key = value]
G --> I[Next key]
H --> I
I --> E
E -- done --> J[projection?.applyProjectionStyles to elementStyle]
J --> K[for key in vars: elementStyle.setProperty]
Reviews (1): Last reviewed commit: "Animate <motion.meta> attributes via set..." | Re-trigger Greptile |
| const renderAsAttrs = element.tagName === "META" | ||
|
|
||
| let key: string | ||
| for (key in style) { | ||
| // CSSStyleDeclaration has [index: number]: string; in the types, so we use that as key type. | ||
| elementStyle[key as unknown as number] = style[key] as string | ||
| if (renderAsAttrs) { | ||
| element.setAttribute(key, style[key] as string) | ||
| } else { | ||
| // CSSStyleDeclaration has [index: number]: string; in the types, so we use that as key type. | ||
| elementStyle[key as unknown as number] = style[key] as string | ||
| } | ||
| } |
There was a problem hiding this comment.
All
style keys routed through setAttribute for META
When renderAsAttrs is true, every key in the style map — including computed values like transform, transformOrigin, opacity, or color — is written via setAttribute rather than elementStyle. For example, animating opacity on a <motion.meta> element would set <meta opacity="0.5" ...> in the DOM instead of an inline style. Since meta elements are invisible this has no practical effect today, but the intent reads as if only attribute-style properties (like content, name, charset) should be routed this way, while CSS properties should either be suppressed or still applied to elementStyle. Consider filtering by the intended attribute keys, or at least documenting that CSS-property keys on <meta> are silently converted to HTML attributes.
| * Elements like <meta> have no rendered styles, so animated values | ||
| * are applied as attributes (e.g. `content` on <meta name="theme-color">). | ||
| */ | ||
| const renderAsAttrs = element.tagName === "META" |
There was a problem hiding this comment.
Other non-visual HTML elements not covered
The fix is scoped to "META" only, but other attribute-driven, non-rendered elements could benefit from the same treatment — e.g. <link> (animating href/media), <base>, or <title>. The current design would require repeating this condition for each tag name. Even if out of scope for this PR, it may be worth a comment noting the extension point, or generalising the guard to a set (NON_VISUAL_TAGS) so future cases are easy to add.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Summary
<motion.meta>elements as DOM attributes (viasetAttribute) rather than inline styles, so animatingcontenton<motion.meta name="theme-color" />actually updates the rendered theme color.contentbetween two colors had no effect.framer-motion/src/motion/__tests__/meta.test.tsxthat animatescontentfrom one rgba color to another and asserts the final attribute value on the element.Bug
Previously, the animated value was written to
element.style.content, which has no effect on a<meta>tag'scontentattribute. The browser's theme color never updated.Fix
In
renderHTML, detectelement.tagName === "META"and route the builtstylevalues throughelement.setAttribute(key, value)instead ofelement.style[key] = value.Fixes #3100
Test plan
yarn buildsucceedsyarn test— all 794 tests pass, including the newmotion.metatestcontentattribute isnull) and passes after🤖 Generated with Claude Code