lucide-icons / lucide

Beautiful & consistent icon toolkit made by the community. Open-source project and a fork of Feather Icons.
https://lucide.dev
ISC License
11.66k stars 539 forks source link

Lucide won't render `data-lucide` if inside `<template>` #2635

Open dotfrag opened 1 week ago

dotfrag commented 1 week ago

Package

Version

0.460.0

Can you reproduce this in the latest version?

Browser

Operating system

Description

I'm using the Content Template element (<template>) to render parts of an HTML form that I use as a template (duh) within JavaScript. Elements with data-lucide inside the template tag do not render.

Steps to reproduce

  1. Minimal setup from guide (all icons)
  2. The following input HTML:
    <div>
       <template><i data-lucide="trash-2" class="size-6 stroke-red-600 mx-auto"></i></template>
       <i data-lucide="trash-2" class="size-6 stroke-red-600 mx-auto"></i>
    </div>
  3. Results in:
        <div>
          <template><i data-lucide="trash-2" class="size-6 stroke-red-600 mx-auto"></i></template>
          <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" data-lucide="trash-2" class="lucide lucide-trash-2 size-6 stroke-red-600 mx-auto"><path d="M3 6h18"></path><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path><line x1="10" x2="10" y1="11" y2="17"></line><line x1="14" x2="14" y1="11" y2="17"></line></svg>
    </div>

Checklist

dotfrag commented 1 week ago

I had a quick look at the code. I am not experienced with JS, but I'll try to help:

It seems that lucide searches for elements using querySelectorAll:

https://github.com/lucide-icons/lucide/blob/49070b4d1f2cb8e32e222ad9ef1826258cf3a7c1/packages/lucide/src/lucide.ts#L19-L22

querySelectorAll doesn't return <template> elements because they are not real elements. However, you can explicitly query them and their content with the following:

// Test to see if the browser supports the HTML template element by checking
// for the presence of the template element's content attribute.
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template#examples
if ("content" in document.createElement("template")) {
  document.querySelectorAll('template').forEach((template) =>
    template.content.querySelectorAll('[data-lucide]').forEach((element) =>
      console.log(element)
    )
  );
}
dotfrag commented 1 week ago

As I said, I'm not experienced enough to contribute with a PR. For anyone who encounters this, you might be able to solve it like it did:

Use pnpm patch and edit the code as below:

diff --git a/dist/esm/lucide.js b/dist/esm/lucide.js
index xxx..xxx 100644
--- a/dist/esm/lucide.js
+++ b/dist/esm/lucide.js
@@ -1562,6 +1562,15 @@ const createIcons = ({ icons = {}, nameAttr = "data-lucide", attrs = {} } = {})
   Array.from(elementsToReplace).forEach(
     (element) => replaceElement(element, { nameAttr, icons, attrs })
   );
+  if ("content" in document.createElement("template")) {
+    const templateElements = document.querySelectorAll('template');
+    templateElements.forEach((template) => {
+      const templateContentElementsToReplace = template.content.querySelectorAll(`[${nameAttr}]`);
+      Array.from(templateContentElementsToReplace).forEach(
+        (element) => replaceElement(element, { nameAttr, icons, attrs })
+      );
+    })
+  }
   if (nameAttr === "data-lucide") {
     const deprecatedElements = document.querySelectorAll("[icon-name]");
     if (deprecatedElements.length > 0) {

If you are using Node with npm, there's patch-package.

If you are using bun, there's bun patch, if you are using Deno I have no idea, sorry.