dangerously-set-html-content
A tiny React component that renders raw HTML strings and actually executes any inline or external script tags inside them.
Repository Health
Technical Analysis
React’s built-in dangerouslySetInnerHTML prop deliberately refuses to execute <script> tags found in the HTML string it renders, because it sets content via the DOM’s innerHTML property, which the browser treats as inert markup for safety reasons. dangerously-set-html-content works around that limitation by using the DOM Range API’s createContextualFragment method to parse the HTML string into a real document fragment, which the browser does execute scripts for, then injects that fragment into a ref-attached container div.
The component is a single, dependency-free (aside from a React peer dependency) function component with two props: html (the string to render) and an optional allowRerender boolean that controls whether subsequent prop changes re-inject content after the first render. It is intentionally narrow in scope, README and typings included, aimed at cases like injecting third-party embed snippets, ad tags, or CMS-authored HTML blocks that must run their own scripts.
What You Get
- A single
<InnerHTML html={...} />component with no runtime dependencies beyond React - Script execution support for both inline
<script>blocks and external<script src=...>tags - An
allowRerenderprop to opt into re-injecting content when thehtmlstring changes after first mount - Bundled TypeScript type declarations (
index.d.ts) for the component’s props - Pass-through of any other props (e.g.
className,id) directly onto the rendered container div
Common Use Cases
- Rendering third-party ad or tracking snippets that include their own
<script>tags - Embedding CMS- or marketing-authored HTML blocks (landing page builders, email templates) that need inline scripts to run
- Injecting widget/embed code (chat widgets, payment buttons, social embeds) supplied as raw HTML+JS strings
- Any case where
dangerouslySetInnerHTMLsilently strips required script behavior
Under The Hood
Architecture
The entire implementation lives in one file, src/index.js — a single function component with no internal module boundaries to speak of. It holds two refs (divRef for the container DOM node and isFirstRender as a mutable guard) and one useEffect that runs whenever html or divRef change. Inside that effect it early-returns if a rerender isn’t allowed and hasn’t been explicitly opted into via allowRerender, otherwise it builds a document fragment from the HTML string and swaps it into the container. There’s no state management or composition to reason about; the entire contract is the two props it accepts and the div it renders via createElement, so a consumer’s mental model of what breaks if this changes reduces to that one effect body.
Tech Stack
The package has a single peer dependency, react (>=18.2.0), and ships plain CommonJS (require/module.exports) rather than ES modules or a bundler-produced dual build. Its dev/build tooling is Create React App’s react-scripts for running tests under jsdom, eslint with the standard + standard-react configs plus eslint-plugin-prettier for lint/format enforcement, and npm-run-all/cross-env to sequence the test:unit/test:lint scripts. Type consumers get a hand-written index.d.ts ambient module declaration rather than being compiled from TypeScript source.
Code Quality
The component is covered by a focused Jest/@testing-library/react test suite (src/index.test.js) exercising six scenarios: rejecting an empty html prop, rendering plain markup, rendering markup with an executing inline script, confirming pass-through props land on the container, and both the allowRerender and no-rerender update paths. Error handling is a single explicit throw when html is missing rather than a silent no-op. There is no CI workflow file in the repository, so test/lint execution on push isn’t automatically enforced, and the source itself is untyped JavaScript with types maintained by hand in a separate .d.ts file rather than derived from the implementation.
API Design
The public surface is deliberately tiny: one component, two meaningful props (html, allowRerender), with any additional props forwarded straight to the rendered div — so there’s effectively zero boilerplate to adopt it beyond import and a single JSX tag. The README documents both props in a table and calls out the rerender caveat explicitly with a link to the PR that introduced it, which is unusually good honesty about a non-obvious default (first-render-only injection) that could otherwise surprise consumers.
Used by 2 apps in this directory
ClearFlask
Product Management · Community
Open-source feedback management and roadmap tool that lets product teams collect, prioritize, and respond to user input — with AI-powered summarization and full self-hosting control.
Grafana
Monitoring · Analytics
The open-source observability platform that unifies metrics, logs, and traces from any data source into dynamic, queryable dashboards.