Skip to content

Conversation

Madoshakalaka
Copy link
Member

@Madoshakalaka Madoshakalaka commented Jul 16, 2025

Description

This PR fixes SVG filter elements that require camelCase names (like feDropShadow) from being incorrectly lowercased, which causes them to not function at all in browsers.

SVG filter effects completely stop working when their element names are lowercased:

<!-- This works in plain HTML -->
<feDropShadow dx="0" dy="0" stdDeviation="10" flood-color="red"/>

<!-- This is what Yew currently generates -->
<fedropshadow dx="0" dy="0" stddeviation="10" flood-color="red"/>

The browser does not recognize <fedropshadow> as a valid SVG filter primitive, so the entire filter effect is ignored.

The Fix

This PR modifies the tag name handling to:

  • Preserve the original casing for known SVG elements (using the existing is_normalised_element_name function)
  • Continue normalizing regular HTML elements to lowercase

This ensures SVG elements work correctly while maintaining the expected behavior for HTML elements.

Example

html! {
    <svg>
        <defs>
            <filter id="glow">
                <feDropShadow dx="0" dy="0" stdDeviation="10" flood-color="red"/>
            </filter>
        </defs>
        <rect width="100" height="100" filter="url(#glow)" />
    </svg>
}

SVG elements like feDropShadow were incorrectly converted to lowercase,
breaking their functionality. Now properly preserves casing for known
SVG elements while normalizing regular HTML elements.

Fixes svg filter rendering issue where filters would not display.
github-actions[bot]
github-actions bot previously approved these changes Jul 16, 2025
Copy link

github-actions bot commented Jul 16, 2025

Visit the preview URL for this PR (updated for commit 3ad175b):

https://yew-rs-api--pr3875-fix-svg-filter-casin-l2azl722.web.app

(expires Sun, 17 Aug 2025 15:21:52 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Copy link

github-actions bot commented Jul 16, 2025

Benchmark - SSR

Yew Master

Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 290.805 291.585 291.070 0.221
Hello World 10 454.659 467.402 457.218 3.738
Function Router 10 1569.800 1600.250 1580.278 9.069
Concurrent Task 10 1005.891 1007.547 1006.514 0.492
Many Providers 10 1093.698 1133.005 1110.804 12.769

Pull Request

Benchmark Round Min (ms) Max (ms) Mean (ms) Standard Deviation
Baseline 10 290.953 293.659 291.324 0.826
Hello World 10 477.401 494.338 484.664 7.029
Function Router 10 1620.884 1643.745 1627.181 6.617
Concurrent Task 10 1004.756 1007.430 1006.142 0.840
Many Providers 10 1075.686 1138.797 1108.013 17.932

Copy link

github-actions bot commented Jul 16, 2025

Size Comparison

examples master (KB) pull request (KB) diff (KB) diff (%)
async_clock 99.421 99.421 0 0.000%
boids 168.201 168.201 0 0.000%
communication_child_to_parent 91.780 91.780 0 0.000%
communication_grandchild_with_grandparent 102.800 102.800 0 0.000%
communication_grandparent_to_grandchild 97.798 97.798 0 0.000%
communication_parent_to_child 87.694 87.694 0 0.000%
contexts 103.902 103.902 0 0.000%
counter 84.495 84.495 0 0.000%
counter_functional 84.851 84.851 0 0.000%
dyn_create_destroy_apps 87.430 87.430 0 0.000%
file_upload 98.548 98.548 0 0.000%
function_memory_game 169.780 169.780 0 0.000%
function_router 336.910 336.910 0 0.000%
function_todomvc 162.883 162.883 0 0.000%
futures 235.953 235.969 +0.016 +0.007%
game_of_life 104.456 104.456 0 0.000%
immutable 194.165 194.165 0 0.000%
inner_html 80.152 80.152 0 0.000%
js_callback 107.565 107.565 0 0.000%
keyed_list 195.413 195.413 0 0.000%
mount_point 83.513 83.513 0 0.000%
nested_list 112.625 112.625 0 0.000%
node_refs 90.870 90.870 0 0.000%
password_strength 1782.886 1782.886 0 0.000%
portals 92.658 92.658 0 0.000%
router 306.364 306.364 0 0.000%
suspense 111.577 111.577 0 0.000%
timer 88.664 88.664 0 0.000%
timer_functional 94.691 94.691 0 0.000%
todomvc 143.130 143.130 0 0.000%
two_apps 85.872 85.872 0 0.000%
web_worker_fib 134.949 134.949 0 0.000%
web_worker_prime 185.107 185.107 0 0.000%
webgl 83.009 83.009 0 0.000%

✅ None of the examples has changed their size significantly.

@Madoshakalaka Madoshakalaka changed the title Fix SVG filter elements being incorrectly lowercased Automatically use camelCase for known svg elements Jul 16, 2025
@Madoshakalaka
Copy link
Member Author

@WorldSEnder what's your stance on this? I see you worked on #2578 which is related to this issue

@Madoshakalaka Madoshakalaka changed the title Automatically use camelCase for known svg elements Preserve camelCase for known svg elements Jul 16, 2025
@Madoshakalaka

This comment was marked as resolved.

@its-the-shrimp
Copy link
Contributor

Why does Yew even meddle with the element names? shouldn't it pass them to the browser as they're specified?

@WorldSEnder
Copy link
Member

WorldSEnder commented Aug 8, 2025

I'm trying to dig through the issues and PRs related to this again. Generally I'm in favor of preserving the casing seen in code going forward instead of normalizing. This would probably move a lot of code that uses dynamic tag names back to literal tags.

The central issue is #1269.

This comment mentions that browsers seemed to be fine with "wrongly" cased elements in svg at some point. The target seems to have moved and invalid casing is no longer acceptable.

Literal tag names are constrained to be valid rust identifiers (stemming from the macro parsing). Which is why we fill the gap between this and browser elements (such as converting underscores to hyphens). Note e.g. that - is not allowed in rust identifiers (technically, - is not an XID_Continue character) yet custom elements must contain a hyphen.

In any case, the original pullrequest in #1266 was aware of all this (although as mentioned above, browsers seem to have gotten more strict). However, it mentions "runtime checks that rely on the casing" and I'm not sure what checks exactly this refers to.

I can find some runtime elements relying on the casing of the tag - there might be more:

  • A check in VTag::new to create an <input /> or <textarea />. Note that the macro does no longer go through this method but relies on the more special __new_input and __new_textarea below. It seems somewhat suspect that the check doesn't have access to the xml namespace, but that's a minor concern for the checked element names.
  • SSR rendering of void elements currently expects a lowercase element name to check against a whitelist.

Given all that, my current stance is that: Lowercasing an element name is only okay if the element is in the HTML namespace. The macro machinery can assume this for additional compile time checks against a blacklist (such as checking void elements or well-known types such as input and textarea) but if these checks pass the user given casing should be preserved.

I think that the name getting emitted by the macro should be dashedname.to_string() in all cases. But obviously, this means a little bit more work in adjusting all the extra checks to be able to handle the ascii-lowercased variant.

github-actions[bot]
github-actions bot previously approved these changes Aug 10, 2025
Copy link

github-actions bot commented Aug 10, 2025

Benchmark - core

Yew Master

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.462 ns      │ 4.213 ns      │ 2.478 ns      │ 2.88 ns       │ 100     │ 1000000000

Pull Request

vnode           fastest       │ slowest       │ median        │ mean          │ samples │ iters
╰─ vnode_clone  2.461 ns      │ 2.491 ns      │ 2.464 ns      │ 2.467 ns      │ 100     │ 1000000000

github-actions[bot]
github-actions bot previously approved these changes Aug 10, 2025
github-actions[bot]
github-actions bot previously approved these changes Aug 10, 2025
@Madoshakalaka
Copy link
Member Author

Madoshakalaka commented Aug 10, 2025

Added a test that actually takes a screenshot and check if the svg is rendered correctly removed the test for now as I'm still figuring out how to take screenshot properly...

github-actions[bot]
github-actions bot previously approved these changes Aug 10, 2025
@Madoshakalaka Madoshakalaka force-pushed the fix-svg-filter-casing branch from 4fb9f9d to f17793f Compare August 10, 2025 13:19
github-actions[bot]
github-actions bot previously approved these changes Aug 10, 2025
Madoshakalaka added a commit to Madoshakalaka/yew that referenced this pull request Aug 21, 2025
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.

3 participants