Skip to content

Animate motion.meta attributes#3705

Closed
mattgperry wants to merge 1 commit intomainfrom
fix/issue-3100-animate-meta-content
Closed

Animate motion.meta attributes#3705
mattgperry wants to merge 1 commit intomainfrom
fix/issue-3100-animate-meta-content

Conversation

@mattgperry
Copy link
Copy Markdown
Collaborator

Summary

  • Apply animated values on <motion.meta> elements as DOM attributes (via setAttribute) rather than inline styles, so animating content on <motion.meta name="theme-color" /> actually updates the rendered theme color.
  • Meta tags are not visually rendered, so the previous style-only render path produced no observable update — animating content between two colors had no effect.
  • Adds a Jest test in framer-motion/src/motion/__tests__/meta.test.tsx that animates content from one rgba color to another and asserts the final attribute value on the element.

Bug

<motion.meta
  name="theme-color"
  initial={{ content: "rgba(255, 0, 0, 1)" }}
  animate={{ content: "rgba(0, 0, 255, 1)" }}
/>

Previously, the animated value was written to element.style.content, which has no effect on a <meta> tag's content attribute. The browser's theme color never updated.

Fix

In renderHTML, detect element.tagName === "META" and route the built style values through element.setAttribute(key, value) instead of element.style[key] = value.

Fixes #3100

Test plan

  • yarn build succeeds
  • yarn test — all 794 tests pass, including the new motion.meta test
  • New unit test fails before the fix (content attribute is null) and passes after

🤖 Generated with Claude Code

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-apps
Copy link
Copy Markdown

greptile-apps Bot commented May 9, 2026

Greptile Summary

This PR fixes animating values on <motion.meta> elements by routing animated style values through element.setAttribute() instead of element.style[key], which had no effect since meta tags are not visually rendered. A focused unit test is added to verify content attribute animation end-to-end.

  • render.ts: Introduces a renderAsAttrs boolean based on element.tagName === \"META\" that switches the per-key write from inline style assignment to setAttribute for the entire style map.
  • meta.test.tsx: New test animating content from one rgba color to another on motion.meta, asserting the final attribute value via getAttribute.

Confidence Score: 4/5

Safe 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 content attribute animation on <meta> tags. The two non-blocking observations — that CSS properties like transform/opacity are silently written as HTML attributes on META elements, and that other non-visual tags are not covered — don't affect any real-world scenario today but represent gaps in the design's generality.

render.ts deserves a second look for the all-or-nothing setAttribute routing; meta.test.tsx is straightforward.

Important Files Changed

Filename Overview
packages/motion-dom/src/render/html/utils/render.ts Adds renderAsAttrs flag for META elements, routing all animated style values through setAttribute instead of inline styles — fixes the theme-color use-case but applies unconditionally to all style keys (including CSS properties like transform/opacity).
packages/framer-motion/src/motion/tests/meta.test.tsx New test that animates content on motion.meta and asserts the final getAttribute("content") value; covers the happy path of the fix.

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]
Loading

Reviews (1): Last reviewed commit: "Animate <motion.meta> attributes via set..." | Re-trigger Greptile

Comment on lines +16 to 26
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
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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!

@mattgperry mattgperry closed this May 9, 2026
@mattgperry mattgperry deleted the fix/issue-3100-animate-meta-content branch May 9, 2026 05:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Animate <motion.meta name="theme-color" content={ANIMATE THIS} />

1 participant