{"article":{"slug":"inline-rendering-with-document-currentscript","title":"Inline rendering with document.currentScript","subtitle":null,"summary":"A tutorial on using document.currentScript to render small bits of dynamic content inline in plain HTML without IDs, classes, querySelectors, or a templating engine, with real-world examples like random greetings and auto-updating footers, plus the catch around synchronous helper scripts.","content_type":"tutorial","language":"en","canonical_url":"https://leanrada.com/notes/inline-rendering-currentscript/","author":{"name":null,"url":null,"person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"leanrada.com","url":"https://leanrada.com/","listing_slug":null,"listing":null},"topics":[{"name":"Web Development","slug":"web-development","url":"https://listedarticles.com/topics/web-development"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Tutorials","slug":"tutorials","url":"https://listedarticles.com/topics/tutorials"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1312,"reading_minutes":6,"published_at":"2025-03-07T00:00:00.000Z","added_at":"2026-10-19T11:15:13.527Z","updated_at":"2026-10-19T11:15:13.527Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/inline-rendering-with-document-currentscript","markdown_url":"https://listedarticles.com/articles/inline-rendering-with-document-currentscript.md","example":false,"citation":"leanrada.com. \"Inline rendering with document.currentScript.\" 7 Mar 2025. https://leanrada.com/notes/inline-rendering-currentscript/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://leanrada.com/notes/inline-rendering-currentscript/"},"body_markdown":"# Inline rendering with document.currentScript\n\nFor quick and dirty rendering of simple dynamic content, you may not need the complexity of a templating language like Handlebars or a PHP backend.\n\nLet’s use the example phrase, *“Come on, it’s `<currentYear>`”*. It should result in *“Come on, it’s [current year]”* when rendered today.\n\nYou can write this directly in HTML—*without IDs, classes, or querySelectors in your JS!* Thanks to the [`document.currentScript`](https://developer.mozilla.org/en-US/docs/Web/API/Document/currentScript) property, we can refer to the *currently running `<script>` element* directly and go from there.\n\nSo the dynamic phrase **“Come on, it’s [current year]”** would now be written as:\n\n```\nCome on, it’s\n<script>\n  document.currentScript.replaceWith(new Date().getFullYear())\n</script>\n```\n\nThe script simply replaces itself with its computed value on the spot.\n\nThe code’s a bit wordy though, but we can *alias* it to a constant like `$` via `$=(...n)=>document.currentScript.replaceWith(...n)`. Then we’d have something reminiscent of [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) in JS.\n\n```\nCome on, it’s <script>$(new Date().getFullYear())</script>\n```\n\nThe code is pretty readable at a glance without context (after you get past the bit of indirection that is the `$` alias).\n\nClick to see the WebComponent version! Disclaimer: This is a joke.\n\nThis is the `RenderJS` custom element. All it does is replace itself with the result of its contents treated as JavaScript code.\n\nTo use it, we must first name the tag. The beloved dollar sign `$` is not allowed, so we use the next best thing—the emoji 💲. Sadly, that’s not enough: Tag names must start with a letter of the alphabet and include a hyphen. As such, we are forced to name it: `j-💲` representing JavaScript.\n\n```` ```\n<script>customElements.define('j-💲', RenderJS);</script>\n``` ````\n\n### Example usage\n\n```` ```\nI overslept by about <j-💲>Math.PI</j-💲> hours this morning.\n``` ````\n\nI overslept by about Math.PI hours this morning.\n\nA [`noscript`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript) fallback would be nice for those that don’t run JS.\n\n```\nCome on, it’s\n<noscript>current year</noscript>\n<script>$(new Date().getFullYear())</script>\n```\n\nThe resulting script-noscript juxtaposition in the markup looks almost like Angular/Vue’s if-else markup, neat.\n\nIIRC, I learned about this technique from the [Surreal](https://github.com/gnat/surreal) library or something similar. But I’m sure this is not a new discovery. These APIs have been standardised for a long time.\n\n## Real world examples\n\nIf you thought this technique is only useful for rendering the current year, you’re mostly right! As an example, I’ve used inline scripts to refer to relative dates in my living pages. Because **“ years ago”** sounds more natural than **“2017”**.\n\n```\nIt was planted\n<noscript>in 2017</noscript>\n<script>$(new Date().getFullYear()-2017, ' years ago')</script>\nbut now it has grown tall and strong.\n```\n\nIt was planted\nbut now it has grown tall and strong.\n\n### Random greeting\n\nAnother example is in my front page, which says a randomly selected greeting on each visit.\n\n![screenshot of my homepage intro section](https://leanrada.com/greeting.png)\n\n```\n<span class=\"intro-line\">\n  <noscript>Hello!</noscript>\n  <script>\n    $([\n      \"Hello!\",\n      \"Hey~~~\",\n      \"What’s up ↑\",\n      \"Hi there →\",\n      \"Hey there →\",\n    ][Date.now() % 5])\n  </script>\n</span>\n```\n\nThe randomiser is just a `Date.now()` with modulo because it was more concise than `Math.floor(Math.random() * 5)`.\n\n### Splitting text for animation\n\nSplit text into characters using inline scripts to generate markup per character which can then be controlled or animated! In my case, I used it to render circular text, but a more common use case is text animation like the following.\n\nIt has been a\nweek.\n\n```\nIt has been a\n<script>document.currentScript.outerHTML=\n  \"supercalifragilisticexpialidocious\"\n    .replace(/./g, c => `<strong>${c}</strong>`)\n</script>\nweek.\n\n<style>\n  strong {\n    display: inline-block;\n    animation: wave 0.3s infinite alternate ease-in-out;\n    &:nth-child(4n + 1) { animation-delay: -0.6s; }\n    &:nth-child(4n + 2) { animation-delay: -0.45s; }\n    &:nth-child(4n + 3) { animation-delay: -0.3s; }\n    &:nth-child(4n + 4) { animation-delay: -0.15s; }\n  }\n  @keyframes wave {\n    to { transform: translateY(-2px); }\n  }\n</style>\n```\n\nWhy import a text splitting library?\n\n### Rendering metadata to reduce duplication\n\nThis post’s heading is dynamically derived from the page title metadata. I only have to define this post’s title once, in the `<title>` tag.\n\n```` ```\n<blog-header>\n  <h1><script>$(document.title)</script></h1>\n  <img src=\"hero.jpg\" alt=\"\" loading=\"lazy\"></img>\n</blog-header>\n``` ````\n\n### Auto-updating footer\n\nHow about an auto-updating copyright notice in the footer which may or may not have legal implications? (IANAL)\n\n```\n<footer>\n  © <script>$(new Date().getFullYear())</script> Mycorp, Ltd.\n</footer>\n```\n\nFor comparison, here’s the StackOverflow/ChatGPT answer:\n\n```\ndocument\n  .getElementById(\"copyright-year\")\n  .textContent = new Date().getFullYear();\n```\n\n```\n<footer>\n  © <span id=\"copyright-year\"></span> Mycorp, Ltd.\n</footer>\n```\n\nWhy pollute the global ID namespace and separate coupled code if we can avoid it?\n\n`` Date().split` `[3] `` is also a short (but very hacky) way to get the year.\n\nAt this point you may be asking, is this technique only really useful for rendering the current year? Maybe, but we can do more than just *rendering* text.\n\nCome on, it’s [current year], the web is rich and interactive!\n\n### The ubiquitous counter app example\n\nThis is not a simple templating example anymore, but shows the power of `currentScript` in [hydrating](https://en.wikipedia.org/wiki/Hydration_(web_development)) self-contained bits of interactive HTML.\n\nCount: 0\n\n```\n<div>\n  Count: <span>0</span>\n  <button>Increment</button>\n  <button>Decrement</button>\n  <script>\n    const [span, increment, decrement] =\n      document.currentScript.parentElement.children;\n    let count = 0;\n    increment.onclick = () => span.replaceChildren(++count);\n    decrement.onclick = () => span.replaceChildren(--count);\n  </script>\n</div>\n```\n\nI used this ‘local script’ pattern all the time in a previous version of this blog. It’s useful when making interactive illustrations in the middle of a long post. You wouldn’t want to put that logic at the very end or start of the file, away from the relevant section! Same goes for styles, now made even better with the [`@scope` rule](https://developer.chrome.com/docs/css-ui/at-scope#prelude-less_scope).\n\nIt’s a good way to manage islands of interactivity.\n\n## The catch\n\nThere are reasons people gravitate to libraries and frameworks. They’re just too convenient.\n\nIf you want to use the alias definition above—the `$` shorthand—then you'd first have to define it at the top of the HTML, **synchronously**. Say you want to use this in multiple pages, so you put this in a common script file and load it via `<script src=\"$.js\"</script>`. This could result in a parser- and render-blocking fetch: potentially very bad for performance!\n\nFor my own cases, I don’t use the alias. I straight up just use `document.currentScript​.replaceWith`. Wish it was [shorter…](https://developer.mozilla.org/en-US/docs/Web/API/Document/write)\n\n~~Also, you cannot do **data-driven templating** this way, in the sense that you have **templates** to apply **data** onto. Metadata such as date published, post title, and tags that are stored in some posts table or in frontmatter somewhere, cannot be used for inline scripting purposes. You can’t fetch data from inline scripts. Therefore, unless data is somehow pre-injected in the global scope, no luck in pure vanilla JS templating. This is where templating languages like [Liquid](https://shopify.github.io/liquid/) really shine.~~\n\n## Update: Data-driven templating\n\nI previously said that you cannot do **data-driven templating** this way (see deleted section above). However, a nice reader has found a way to do so (thanks Amier)!\n\nAll you need is to save the `currentScript` in a variable, then you can refer to it in any async operation!\n\nHere’s the code for that: [jsfiddle](https://jsfiddle.net/0xh2mg8f/).\n\n```\n<ul class=\"posts\">\n  <script>\n    const script = document.currentScript;\n    fetch(\"/posts.json\") \n      .then(response => response.json()) \n      .then(data => data.map(p => (\n        `<li><a href=\"${p.url}\">${p.title}</a></li>`\n      )).join(\"\"))\n      .then(html => script.outerHTML = html);\n  </script>\n</ul>\n```\n\n**Reminder:** If using `innerHTML` or `outerHTML`, sanitise the HTML first, especially if you fetched it externally!\n\nIt incurs an extra HTTP request on the client, though, unlike backend-side templating systems.\n\nFor my site, I don’t need a templating system—I use direct patching to data-drive my HTML (in which the source and the output files are the same).\n\nEven if you use a templating framework or a static site generator, inline scripts remain useful!\n\n## Further reading\n\n- [Surreal](https://github.com/gnat/surreal) - a library that offers this technique, plus other jQuery-style helpers. Note the synchronous script tag loading issue though!\n- [currentScript discussion in SvelteKit](https://github.com/sveltejs/kit/issues/2221) - this as an alternative to global IDs for self-hydrating things. In the end they went with generated IDs. :|\n\n## Appendix\n\n[`document.write()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/write) used to (?) work like this for inline rendering, but it’s now deprecated because it had inconsistent behaviour.\n\n```` ```\nCome on, it’s\n<script>document.write(new Date().getFullYear())</script>,\nstop using <code>document.write</code>!\n``` ````\n","body_html":"<h1 id=\"inline-rendering-with-document-currentscript\">Inline rendering with document.currentScript</h1>\n<p>For quick and dirty rendering of simple dynamic content, you may not need the complexity of a templating language like Handlebars or a PHP backend.</p>\n<p>Let’s use the example phrase, <em>“Come on, it’s <code>&lt;currentYear&gt;</code>”</em>. It should result in <em>“Come on, it’s [current year]”</em> when rendered today.</p>\n<p>You can write this directly in HTML—<em>without IDs, classes, or querySelectors in your JS!</em> Thanks to the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/currentScript\" rel=\"nofollow ugc noopener\"><code>document.currentScript</code></a> property, we can refer to the <em>currently running <code>&lt;script&gt;</code> element</em> directly and go from there.</p>\n<p>So the dynamic phrase <strong>“Come on, it’s [current year]”</strong> would now be written as:</p>\n<pre><code>Come on, it’s\n&lt;script&gt;\n  document.currentScript.replaceWith(new Date().getFullYear())\n&lt;/script&gt;</code></pre>\n<p>The script simply replaces itself with its computed value on the spot.</p>\n<p>The code’s a bit wordy though, but we can <em>alias</em> it to a constant like <code>$</code> via <code>$=(...n)=&gt;document.currentScript.replaceWith(...n)</code>. Then we’d have something reminiscent of <a href=\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals\" rel=\"nofollow ugc noopener\">template literals</a> in JS.</p>\n<pre><code>Come on, it’s &lt;script&gt;$(new Date().getFullYear())&lt;/script&gt;</code></pre>\n<p>The code is pretty readable at a glance without context (after you get past the bit of indirection that is the <code>$</code> alias).</p>\n<p>Click to see the WebComponent version! Disclaimer: This is a joke.</p>\n<p>This is the <code>RenderJS</code> custom element. All it does is replace itself with the result of its contents treated as JavaScript code.</p>\n<p>To use it, we must first name the tag. The beloved dollar sign <code>$</code> is not allowed, so we use the next best thing—the emoji 💲. Sadly, that’s not enough: Tag names must start with a letter of the alphabet and include a hyphen. As such, we are forced to name it: <code>j-💲</code> representing JavaScript.</p>\n<p><code> ```\n&lt;script&gt;customElements.define(&#39;j-💲&#39;, RenderJS);&lt;/script&gt;\n``` </code></p>\n<h3 id=\"example-usage\">Example usage</h3>\n<p><code> ```\nI overslept by about &lt;j-💲&gt;Math.PI&lt;/j-💲&gt; hours this morning.\n``` </code></p>\n<p>I overslept by about Math.PI hours this morning.</p>\n<p>A <a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Element/noscript\" rel=\"nofollow ugc noopener\"><code>noscript</code></a> fallback would be nice for those that don’t run JS.</p>\n<pre><code>Come on, it’s\n&lt;noscript&gt;current year&lt;/noscript&gt;\n&lt;script&gt;$(new Date().getFullYear())&lt;/script&gt;</code></pre>\n<p>The resulting script-noscript juxtaposition in the markup looks almost like Angular/Vue’s if-else markup, neat.</p>\n<p>IIRC, I learned about this technique from the <a href=\"https://github.com/gnat/surreal\" rel=\"nofollow ugc noopener\">Surreal</a> library or something similar. But I’m sure this is not a new discovery. These APIs have been standardised for a long time.</p>\n<h2 id=\"real-world-examples\">Real world examples</h2>\n<p>If you thought this technique is only useful for rendering the current year, you’re mostly right! As an example, I’ve used inline scripts to refer to relative dates in my living pages. Because <strong>“ years ago”</strong> sounds more natural than <strong>“2017”</strong>.</p>\n<pre><code>It was planted\n&lt;noscript&gt;in 2017&lt;/noscript&gt;\n&lt;script&gt;$(new Date().getFullYear()-2017, &#39; years ago&#39;)&lt;/script&gt;\nbut now it has grown tall and strong.</code></pre>\n<p>It was planted\nbut now it has grown tall and strong.</p>\n<h3 id=\"random-greeting\">Random greeting</h3>\n<p>Another example is in my front page, which says a randomly selected greeting on each visit.</p>\n<figure><img src=\"https://leanrada.com/greeting.png\" alt=\"screenshot of my homepage intro section\" loading=\"lazy\" decoding=\"async\" referrerpolicy=\"no-referrer\" /></figure>\n<pre><code>&lt;span class=&quot;intro-line&quot;&gt;\n  &lt;noscript&gt;Hello!&lt;/noscript&gt;\n  &lt;script&gt;\n    $([\n      &quot;Hello!&quot;,\n      &quot;Hey~~~&quot;,\n      &quot;What’s up ↑&quot;,\n      &quot;Hi there →&quot;,\n      &quot;Hey there →&quot;,\n    ][Date.now() % 5])\n  &lt;/script&gt;\n&lt;/span&gt;</code></pre>\n<p>The randomiser is just a <code>Date.now()</code> with modulo because it was more concise than <code>Math.floor(Math.random() * 5)</code>.</p>\n<h3 id=\"splitting-text-for-animation\">Splitting text for animation</h3>\n<p>Split text into characters using inline scripts to generate markup per character which can then be controlled or animated! In my case, I used it to render circular text, but a more common use case is text animation like the following.</p>\n<p>It has been a\nweek.</p>\n<pre><code>It has been a\n&lt;script&gt;document.currentScript.outerHTML=\n  &quot;supercalifragilisticexpialidocious&quot;\n    .replace(/./g, c =&gt; `&lt;strong&gt;${c}&lt;/strong&gt;`)\n&lt;/script&gt;\nweek.\n\n&lt;style&gt;\n  strong {\n    display: inline-block;\n    animation: wave 0.3s infinite alternate ease-in-out;\n    &amp;:nth-child(4n + 1) { animation-delay: -0.6s; }\n    &amp;:nth-child(4n + 2) { animation-delay: -0.45s; }\n    &amp;:nth-child(4n + 3) { animation-delay: -0.3s; }\n    &amp;:nth-child(4n + 4) { animation-delay: -0.15s; }\n  }\n  @keyframes wave {\n    to { transform: translateY(-2px); }\n  }\n&lt;/style&gt;</code></pre>\n<p>Why import a text splitting library?</p>\n<h3 id=\"rendering-metadata-to-reduce-duplication\">Rendering metadata to reduce duplication</h3>\n<p>This post’s heading is dynamically derived from the page title metadata. I only have to define this post’s title once, in the <code>&lt;title&gt;</code> tag.</p>\n<p><code> ```\n&lt;blog-header&gt;\n  &lt;h1&gt;&lt;script&gt;$(document.title)&lt;/script&gt;&lt;/h1&gt;\n  &lt;img src=&quot;hero.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot;&gt;&lt;/img&gt;\n&lt;/blog-header&gt;\n``` </code></p>\n<h3 id=\"auto-updating-footer\">Auto-updating footer</h3>\n<p>How about an auto-updating copyright notice in the footer which may or may not have legal implications? (IANAL)</p>\n<pre><code>&lt;footer&gt;\n  © &lt;script&gt;$(new Date().getFullYear())&lt;/script&gt; Mycorp, Ltd.\n&lt;/footer&gt;</code></pre>\n<p>For comparison, here’s the StackOverflow/ChatGPT answer:</p>\n<pre><code>document\n  .getElementById(&quot;copyright-year&quot;)\n  .textContent = new Date().getFullYear();</code></pre>\n<pre><code>&lt;footer&gt;\n  © &lt;span id=&quot;copyright-year&quot;&gt;&lt;/span&gt; Mycorp, Ltd.\n&lt;/footer&gt;</code></pre>\n<p>Why pollute the global ID namespace and separate coupled code if we can avoid it?</p>\n<p><code>Date().split` `[3]</code> is also a short (but very hacky) way to get the year.</p>\n<p>At this point you may be asking, is this technique only really useful for rendering the current year? Maybe, but we can do more than just <em>rendering</em> text.</p>\n<p>Come on, it’s [current year], the web is rich and interactive!</p>\n<h3 id=\"the-ubiquitous-counter-app-example\">The ubiquitous counter app example</h3>\n<p>This is not a simple templating example anymore, but shows the power of <code>currentScript</code> in <a href=\"https://en.wikipedia.org/wiki/Hydration_(web_development)\" rel=\"nofollow ugc noopener\">hydrating</a> self-contained bits of interactive HTML.</p>\n<p>Count: 0</p>\n<pre><code>&lt;div&gt;\n  Count: &lt;span&gt;0&lt;/span&gt;\n  &lt;button&gt;Increment&lt;/button&gt;\n  &lt;button&gt;Decrement&lt;/button&gt;\n  &lt;script&gt;\n    const [span, increment, decrement] =\n      document.currentScript.parentElement.children;\n    let count = 0;\n    increment.onclick = () =&gt; span.replaceChildren(++count);\n    decrement.onclick = () =&gt; span.replaceChildren(--count);\n  &lt;/script&gt;\n&lt;/div&gt;</code></pre>\n<p>I used this ‘local script’ pattern all the time in a previous version of this blog. It’s useful when making interactive illustrations in the middle of a long post. You wouldn’t want to put that logic at the very end or start of the file, away from the relevant section! Same goes for styles, now made even better with the <a href=\"https://developer.chrome.com/docs/css-ui/at-scope#prelude-less_scope\" rel=\"nofollow ugc noopener\"><code>@scope</code> rule</a>.</p>\n<p>It’s a good way to manage islands of interactivity.</p>\n<h2 id=\"the-catch\">The catch</h2>\n<p>There are reasons people gravitate to libraries and frameworks. They’re just too convenient.</p>\n<p>If you want to use the alias definition above—the <code>$</code> shorthand—then you&#39;d first have to define it at the top of the HTML, <strong>synchronously</strong>. Say you want to use this in multiple pages, so you put this in a common script file and load it via <code>&lt;script src=&quot;$.js&quot;&lt;/script&gt;</code>. This could result in a parser- and render-blocking fetch: potentially very bad for performance!</p>\n<p>For my own cases, I don’t use the alias. I straight up just use <code>document.currentScript​.replaceWith</code>. Wish it was <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/write\" rel=\"nofollow ugc noopener\">shorter…</a></p>\n<p><del>Also, you cannot do <strong>data-driven templating</strong> this way, in the sense that you have <strong>templates</strong> to apply <strong>data</strong> onto. Metadata such as date published, post title, and tags that are stored in some posts table or in frontmatter somewhere, cannot be used for inline scripting purposes. You can’t fetch data from inline scripts. Therefore, unless data is somehow pre-injected in the global scope, no luck in pure vanilla JS templating. This is where templating languages like <a href=\"https://shopify.github.io/liquid/\" rel=\"nofollow ugc noopener\">Liquid</a> really shine.</del></p>\n<h2 id=\"update-data-driven-templating\">Update: Data-driven templating</h2>\n<p>I previously said that you cannot do <strong>data-driven templating</strong> this way (see deleted section above). However, a nice reader has found a way to do so (thanks Amier)!</p>\n<p>All you need is to save the <code>currentScript</code> in a variable, then you can refer to it in any async operation!</p>\n<p>Here’s the code for that: <a href=\"https://jsfiddle.net/0xh2mg8f/\" rel=\"nofollow ugc noopener\">jsfiddle</a>.</p>\n<pre><code>&lt;ul class=&quot;posts&quot;&gt;\n  &lt;script&gt;\n    const script = document.currentScript;\n    fetch(&quot;/posts.json&quot;) \n      .then(response =&gt; response.json()) \n      .then(data =&gt; data.map(p =&gt; (\n        `&lt;li&gt;&lt;a href=&quot;${p.url}&quot;&gt;${p.title}&lt;/a&gt;&lt;/li&gt;`\n      )).join(&quot;&quot;))\n      .then(html =&gt; script.outerHTML = html);\n  &lt;/script&gt;\n&lt;/ul&gt;</code></pre>\n<p><strong>Reminder:</strong> If using <code>innerHTML</code> or <code>outerHTML</code>, sanitise the HTML first, especially if you fetched it externally!</p>\n<p>It incurs an extra HTTP request on the client, though, unlike backend-side templating systems.</p>\n<p>For my site, I don’t need a templating system—I use direct patching to data-drive my HTML (in which the source and the output files are the same).</p>\n<p>Even if you use a templating framework or a static site generator, inline scripts remain useful!</p>\n<h2 id=\"further-reading\">Further reading</h2>\n<ul><li><a href=\"https://github.com/gnat/surreal\" rel=\"nofollow ugc noopener\">Surreal</a> - a library that offers this technique, plus other jQuery-style helpers. Note the synchronous script tag loading issue though!</li><li><a href=\"https://github.com/sveltejs/kit/issues/2221\" rel=\"nofollow ugc noopener\">currentScript discussion in SvelteKit</a> - this as an alternative to global IDs for self-hydrating things. In the end they went with generated IDs. :|</li></ul>\n<h2 id=\"appendix\">Appendix</h2>\n<p><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Document/write\" rel=\"nofollow ugc noopener\"><code>document.write()</code></a> used to (?) work like this for inline rendering, but it’s now deprecated because it had inconsistent behaviour.</p>\n<p><code> ```\nCome on, it’s\n&lt;script&gt;document.write(new Date().getFullYear())&lt;/script&gt;,\nstop using &lt;code&gt;document.write&lt;/code&gt;!\n``` </code></p>","headings":[{"level":1,"text":"Inline rendering with document.currentScript","id":"inline-rendering-with-document-currentscript"},{"level":3,"text":"Example usage","id":"example-usage"},{"level":2,"text":"Real world examples","id":"real-world-examples"},{"level":3,"text":"Random greeting","id":"random-greeting"},{"level":3,"text":"Splitting text for animation","id":"splitting-text-for-animation"},{"level":3,"text":"Rendering metadata to reduce duplication","id":"rendering-metadata-to-reduce-duplication"},{"level":3,"text":"Auto-updating footer","id":"auto-updating-footer"},{"level":3,"text":"The ubiquitous counter app example","id":"the-ubiquitous-counter-app-example"},{"level":2,"text":"The catch","id":"the-catch"},{"level":2,"text":"Update: Data-driven templating","id":"update-data-driven-templating"},{"level":2,"text":"Further reading","id":"further-reading"},{"level":2,"text":"Appendix","id":"appendix"}]}}