Skip to content

feat: mimicks dangerouslySetInnerHTML behavior#12

Closed
lukal-x wants to merge 2 commits intoDavidVujic:mainfrom
lukal-x:feature/dangerouslySetInnerHTML
Closed

feat: mimicks dangerouslySetInnerHTML behavior#12
lukal-x wants to merge 2 commits intoDavidVujic:mainfrom
lukal-x:feature/dangerouslySetInnerHTML

Conversation

@lukal-x
Copy link
Copy Markdown

@lukal-x lukal-x commented Sep 6, 2025

Implementation of dangerouslySetInnerHTML attribute just like in React https://react.dev/reference/react-dom/components/common#dangerously-setting-the-inner-html

Description

Allows one to pass raw HTML strings to an element, overriding the HTML escaping routine:

data = [
    "div",
    [
        "a",
        {
            "href": "/location",
            "dangerouslySetInnerHTML": {"__html": "Location →"},
        },
        "Location",
    ],
]

assert render(data) != '<div><a href="https://github.com/location">Location &amp;rarr;</a></div>'

Motivation and Context

This is useful to - for example - render content of an SVG with hiccup, or HTML entities like © (&copy;) as another example.

Although I did check that changing the _escape function to do html.unescape(html.escape("&copy; Python Hiccup 2025")) can accomplish the same. I can include it in this PR if it's wanted. (edit: ignore this, bad idea)

The way it's implemented is by adding a nullable string parameter to _to_html called rename which, when set, renames the HTML element about to get rendered. By doing this we can detect the setDangerouslyInnerHTML attribute and early return a recursive re-render of a new version of the element but pretending it's a <style> or <script> tag - both of which aren't supposed to get escaped per-spec - and renaming it back to its original name.

How Has This Been Tested?

Unit tests and with an SVG:

Screenshot_2025-09-06_08-54-41

It might prove beneficial to stress test it, I do write a lot of Python with FP and try hard to avoid bottlenecks however I might've missed something.

Perhaps a switch to comparing strings to detect usage of dangerouslySetInnerHTML might improve performance over filtering the attributes of every element in the tree.

Also I'm aware the sizable change in _to_html might somehow fit better elsewhere but I'm not yet sure where.

Types of changes

  • [ ?] Bug fix (non-breaking change which fixes an issue)
  • [x ] New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Checklist:

Should I also mention something in the docs? Is it significant enough?

codescene-delta-analysis[bot]

This comment was marked as outdated.

@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud bot commented Sep 6, 2025

@DavidVujic DavidVujic self-assigned this Sep 6, 2025
@DavidVujic
Copy link
Copy Markdown
Owner

Thank you ⭐ I'll have a look!

Comment on lines +156 to +165
data = [
"div",
[
"a",
{
"href": "/location",
"dangerouslySetInnerHTML": {"__html": "Location &rarr;"},
},
"Location",
],
Copy link
Copy Markdown
Owner

@DavidVujic DavidVujic Sep 6, 2025

Choose a reason for hiding this comment

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

I have a question: why not adding the location &arr; as a child html node to a?

I didn't know about the dangerouslySetInnerHTML before. Is that mainly for the React parser? I'm thinking if it would make sense to add the child directly. Please correct me if I misunderstand!

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I think I understand the problem better, sorry for the noise! I will continue reviewing 😄

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Essentially there's scenarios where a blanket escape is unwanted because prevents you from inlining contents of an SVG for example, or some kind of markup that you load from a trusted source.

"Trusted" is the key term here. That's why the dangerously prefix.
It's from react yeah so I figure it's a recognizable enough idiom.

What I said about html.unescape is a bad idea btw, I'll edit the first comment to strike it out.

@DavidVujic
Copy link
Copy Markdown
Owner

What do you think about this alternative approach? Allowing to pass in a function, as a custom render where you can add things that shouldn't be escaped.

Here's what I have experimented with so far:
#13

@lukal-x
Copy link
Copy Markdown
Author

lukal-x commented Sep 7, 2025

Nice! It's not only more elegant but also more in line with https://weavejester.github.io/hiccup/hiccup2.core.html#var-raw

@lukal-x lukal-x closed this Sep 7, 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.

2 participants