2

I'm building a search auto-suggest component where the results are rendered with hyperHTML. The matching string part of the suggestions returned from the server should be highlighted.

I'm using a RegEx and String.prototype.replace to highlight the matching part, but somehow I can't manage to output the return value of it to HTML. It just renders the <strong> tags as strings.

I tried quite a bit of different approaches to solve this but without any success and am running out of ideas...

This is my rendering function:

const suggestionsContainer = document.querySelector(
  ".js-suggestions-container"
);
const suggestions = [{
    title: "lorem ipsum dolor sit amet",
    url: "#"
  },
  {
    title: "lorem ipsum dolor sit amet",
    url: "#"
  }
];
let query = "ipsum";

function renderSuggestions(suggestions, query) {
  const queryRegEx = new RegExp(query, "gi");
  hyperHTML.bind(suggestionsContainer)`
      ${suggestions.map((suggestion) => hyperHTML.wire(suggestion)`
        <a href="${suggestion.url}">
          ${hyperHTML.wire()`${suggestion.title.replace(queryRegEx, "<strong>$&</strong>")}`}
        </a>
      `)}
  `;
}

renderSuggestions(suggestions, query);
a {
  display: block;
  margin: 1rem 0;
}
<script src="https://unpkg.com/hyperhtml@latest/min.js"></script>
<div class="js-suggestions-container"></div>
Tushar Walzade
  • 3,737
  • 4
  • 33
  • 56
Felix Wienberg
  • 921
  • 12
  • 19
  • Are you sure you need to put the tag as `` instead of `` ? And also I'd suggest rather something like ... as the b-tag should be used as a last resort. – casenonsensitive Jul 14 '20 at 17:00
  • @casenonsensitive Yes, you're right. I'd meant to use `` and not ``. I edited the post to correct it. But that doesn't change anything about the main problem that the tag is not rendered as html but as a string, regardless of the kind of html tag I use. – Felix Wienberg Jul 14 '20 at 17:12
  • I'm guessing the `a` element is created correctly, so the problem would be inside it. Have you tried making it more easy, replacing the `${wire()\`${suggestion.title.replace(queryRegEx, '$&')}\`}` with `${suggestion.title.replace(queryRegEx, '$&')}` ? – casenonsensitive Jul 14 '20 at 20:13
  • @casenonsensitive Yes, tried that as well. Makes no difference. I replaced the code example in my original question with a runnable code snippet to make it a bit easier to understand/reproduce. – Felix Wienberg Jul 15 '20 at 05:32

1 Answers1

2

As you can see in this CodePen, the only change you need is to explicitly ask for html:

  ${suggestions.map((suggestion) => hyperHTML.wire(suggestion)`
    <a href="${suggestion.url}">
      ${{html: suggestion.title.replace(queryRegEx, "<strong>$&</strong>")}}
    </a>
  `)}

The {html: ...} is the most obvious way, but hyperHTML also injects arrays as HTML, but that might be unexpected, while both lighterhtml and micro html are safer by default, and interpolated content must be always explicitly injected.

P.S. wiring just text as content is also almost never necessary

Andrea Giammarchi
  • 3,038
  • 15
  • 25