Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(autocomplete-js): enable HTML templating #920

Merged
merged 29 commits into from Apr 7, 2022
Merged

Conversation

sarahdayan
Copy link
Member

@sarahdayan sarahdayan commented Mar 16, 2022

This PR introduces HTML templating to Autocomplete.

Try HTML templates in the sandbox →

Summary

The autocomplete-js package is an agnostic virtual DOM renderer, to be used in JavaScript, Preact, React, or Vue projects. It expects virtual nodes to describe UIs, which means Autocomplete users are expected to provide templates as virtual node trees.

Building virtual nodes can be done either with createElement (provided in every template) or using JSX. However, none of these options are user-friendly to vanilla JavaScript users, especially those who don't have a build step.

HTML templating in Autocomplete allows users to:

  • Pass templates as HTML strings
  • Not rely on the provided createElement function or on JSX
  • Not having to install a UI library (such as Preact) at all
  • Not having to use dangerous APIs such as __dangerouslySetInnerHTML to provide HTML templates

Under the hood, autocomplete-js still uses a virtual DOM. It still works with JSX and createElement, and still provides the same speed and safety for all template usages.

Usage

import { autocomplete } from '@algolia/autocomplete-js';

autocomplete({
  container: '#autocomplete',
  placeholder: 'Search',
  getSources({ query }) {
    return [
      {
        // ...
        templates: {
          item({ item, components, html }) {
            return html`<div class="aa-ItemWrapper">
              <div class="aa-ItemContent">
                <div
                  class="aa-ItemIcon aa-ItemIcon--picture aa-ItemIcon--alignTop"
                >
                  <img
                    src="${item.image}"
                    alt="${item.name}"
                    width="40"
                    height="40"
                  />
                </div>

                <div class="aa-ItemContentBody">
                  <div class="aa-ItemContentTitle">
                    ${components.Highlight({ hit: item, attribute: 'name' })}
                  </div>
                  <div class="aa-ItemContentDescription">
                    By <strong>${item.brand}</strong> in ${' '}
                    <strong>${item.categories[0]}</strong>
                  </div>
                </div>
              </div>
            </div>`;
          },
        },
      },
    ];
  },
});

Templates now expose an html function. This function is a tagged template, which lets users provide templates as interpolated strings. This generates a virtual node tree (just like JSX or createElement) while providing a simple HTML string.

One benefit over classic HTML templates injected in a container is that these templates accept inline event handlers (e.g., onClick), just like JSX. It facilitates interactivity and garbage collection of event handlers in many situations.

The html function is also available in the render and renderNoresults options, so users can customize the layout of their Autocomplete panel before rendering. Both options also expose a render function, so there's no need to install any virtual DOM dependency at all on the user's end.

import { autocomplete } from '@algolia/autocomplete-js';

autocomplete({
  // ...
  render({ children, render, html }, root) {
    render(html`<div class="aa-SomeResults">${children}</div>`, root);
  },
  renderNoResults({ children, render, html }, root) {
    render(html`<div class="aa-NoResults">${children}</div>`, root);
  },
});

IE 11 compatibility

Tagged templates aren't compatible with Internet Explorer 11, but there are ways to use the html function in IE 11. If you need to support IE 11, please refer to the Autocomplete templates documentation to either transform your code, or use an IE 11-compatible shim.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Mar 16, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 40035ff:

Sandbox Source
@algolia/autocomplete-example-github-repositories-custom-plugin Configuration
@algolia/autocomplete-example-instantsearch Configuration
algolia/autocomplete Configuration
@algolia/autocomplete-example-preview-panel-in-modal Configuration
@algolia/autocomplete-example-react-renderer Configuration
@algolia/autocomplete-example-starter-algolia Configuration
@algolia/autocomplete-example-starter Configuration
@algolia/autocomplete-example-reshape Configuration
@algolia/autocomplete-example-vue Configuration
@algolia/autocomplete-example-html-templates PR

@sarahdayan sarahdayan force-pushed the feat/html-templating branch 4 times, most recently from 628e069 to 78a0479 Compare March 18, 2022 22:23
@sarahdayan sarahdayan force-pushed the feat/html-templating branch 4 times, most recently from 74e16bf to 91940e5 Compare March 31, 2022 14:18
@sarahdayan sarahdayan marked this pull request as ready for review March 31, 2022 23:16
@sarahdayan sarahdayan requested review from a team, dhayab, FabienMotte, francoischalifour and Haroenv and removed request for a team and FabienMotte March 31, 2022 23:16
Copy link
Contributor

@Haroenv Haroenv left a comment

Choose a reason for hiding this comment

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

👍

Copy link
Member

@dhayab dhayab left a comment

Choose a reason for hiding this comment

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

👏 👏 👏

@sarahdayan
Copy link
Member Author

I'll merge once the docs are ready (so we don't hog potential bug fixes if needed in the meantime).

@absemetov
Copy link

Hi @sarahdayan! I have problem like this 1209
How do you handle image error?

 <img
    src="${item.img}"
    onerror="this.onerror = null; this.src = '/icons/flower3.svg';"
    alt="${item.name}"
    width="100"
    height="100"
 />

@absemetov
Copy link

absemetov commented Aug 24, 2022

Solution!

item({item, html}) {
  const imageOnErrorHandler = (event) => event.currentTarget.src = "/icons/flower3.svg";
  return html`
    <img
      src="${item.img}"
      onerror=${imageOnErrorHandler}
    />`
}

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.

None yet

5 participants