> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Displaying items with templates

> Templates let you customize the display of your autocomplete items.

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

<Tip>
  Autocomplete is also available as an experimental widget in InstantSearch,
  making it easier to integrate into your search experience.
  For more information,
  see the API reference for [InstantSearch.js](/doc/api-reference/widgets/autocomplete/js) or
  [React InstantSearch](/doc/api-reference/widgets/autocomplete/react).
</Tip>

Once you've set up your [data sources](/doc/ui-libraries/autocomplete/core-concepts/sources),
you need to define how they display.
Autocomplete templates let you customize the appearance and layout of each item.

## Render each item

Autocomplete uses a virtual DOM for rendering.
This ensures optimal performance even with frequent updates,
safeguards against cross-site scripting (XSS) attacks, and supports inline event handling.

Templates can return any valid virtual DOM elements (VNodes).

For example, templates can return strings, HTML strings, or Preact components.

### Strings

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item }) {
            return item.name;
          },
        },
      },
    ];
  },
});
```

### HTML strings

Templates can return HTML strings using an `html` tagged template:

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item, html }) {
            return html`<div>${item.name}</div>`;
          },
        },
      },
    ];
  },
});
```

### Preact components

Templates can return [Preact](https://preactjs.com/) components using JSX:

```jsx JSX icon=code theme={"system"}
/** @jsx h */
import { h } from "preact";
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item }) {
            return <div>{item.name}</div>;
          },
        },
      },
    ];
  },
});
```

<Note>
  Autocomplete uses [Preact 10](https://preactjs.com/guide/v10/whats-new/) to render templates by default.
  It isn't compatible with earlier versions.
</Note>

## Return HTML

Native HTML elements aren't valid VNodes,
which means you can't return a template string that contains HTML,
or an HTML element.
But if you're not using a virtual DOM implementation in your app,
**you can still return HTML with the provided `html` tagged template**.

Every Autocomplete template provides an `html` function that you can use as a [tagged template](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates).
Using `html` lets you provide templates as an HTML string
It works directly in the browser without a build step.

<Note>
  The `html` function is only available starting from Autocomplete v1.6.0.
</Note>

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item, html }) {
            return html`<div>
              <img src="${item.image}" alt="${item.name}" />
              <div>${item.name}</div>
            </div>`;
          },
        },
      },
    ];
  },
});
```

<Note>
  Internet Explorer 11 doesn't support tagged template literals. If you need to support Internet Explorer 11, check out the [suggested solutions](#internet-explorer-11-support).
</Note>

### Components and layouts

You can use the provided [components](#components) in your templates by using their function form or interpolating them.

<CodeGroup>
  ```js Function theme={"system"}
  import { autocomplete } from "@algolia/autocomplete-js";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            item({ item, components, html }) {
              return html`<div>
                <img src="${item.image}" alt="${item.name}" />
                <div>
                  ${components.Highlight({ hit: item, attribute: "name" })}
                </div>
              </div>`;
            },
          },
        },
      ];
    },
  });
  ```

  ```js Interpolation theme={"system"}
  import { autocomplete } from "@algolia/autocomplete-js";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            item({ item, html }) {
              return html`<div>
                <img src="${item.image}" alt="${item.name}" />
                <div>
                  <${components.Highlight} hit="${item}" attribute="name" />
                </div>
              </div>`;
            },
          },
        },
      ];
    },
  });
  ```
</CodeGroup>

The `html` function is also exposed in [`render`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#param-render) and [`renderNoResults`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#param-render-no-results) to customize the panel layout.

### Loops and conditional rendering

You can use plain JavaScript to build dynamic templates.

For example, use [`Array.map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) to loop over an array and display a list.

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item, html }) {
            return html`<div>
              <img src="${item.image}" alt="${item.name}" />
              <div>${item.name}</div>
              <ul>
                ${item.categories.map(
                  (category) =>
                    html`<li key="${category.id}">${category.label}</li>`,
                )}
              </ul>
            </div>`;
          },
        },
      },
    ];
  },
});
```

<Note>
  Passing a unique `key` attribute is helpful when mapping over items. It helps the virtual DOM keep track of each element when they change, and update the UI efficiently.
</Note>

To conditionally render a part of your UI, use a [short-circuit](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND) or a [ternary](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) operator.

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item, html }) {
            return html`<div>
              <img src="${item.image}" alt="${item.name}" />
              <div>${item.name}</div>
              <div>
                ${item.rating !== null ? `Rating: ${item.rating}` : "Unrated"}
              </div>
            </div>`;
          },
        },
      },
    ];
  },
});
```

### HTML in variables

**Only the HTML provided as a string literal is evaluated.** HTML in variables (for example, stored in Algolia <Records />) isn't supported and is rendered as-is.

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item, html }) {
            const name = "<p>Jimmie Barninger</p>";

            // This returns a `<div>` with text "<p>Jimmie Barninger</p>"
            return html`<div>${name}</div>`;
          },
        },
      },
    ];
  },
});
```

### Internet Explorer 11 support

**You can't use `html` as a tagged template in Internet Explorer 11.**
Depending on your project setup, you can work around this problem to still use `html` while providing compatible code to your Internet Explorer 11 users.

#### With Babel

If you have a build step and are using [Babel](https://babeljs.io/) to compile your code for legacy browsers, you can transform all `html` expressions into regular function calls.

The recommended setup is to use [`@babel/preset-env`](https://babeljs.io/docs/babel-preset-env), which provides this transformation along with other common ones based on a list of browsers to support.

```json .babelrc icon=braces theme={"system"}
{
  "presets": [["@babel/preset-env"]]
}
```

<Note>
  This transform is available as a [Babel plugin](https://babeljs.io/docs/babel-plugin-transform-template-literals).
</Note>

#### With a shim

If you don't have a build step in your project,
write a <Tooltip tip="Piece of code to correct the behavior of existing code">shim</Tooltip>.
Tagged templates are regular functions with a specific signature, so you can wrap their calls with a friendlier API to avoid using tagged template notation.

This function takes templates as static strings or an array of interspersed chunks, splits them, and passes them to the `html` function.

<CodeGroup>
  ```js Shim theme={"system"}
  function htmlShim(template, html) {
    if (typeof template === "string") {
      return html([template]);
    }

    const parts = template.reduce(
      (acc, part, index) => {
        const isEven = index % 2 === 0;

        acc[Math.abs(Number(!isEven))].push(part);

        return acc;
      },
      [[], []],
    );

    return html(parts[0], ...parts[1]);
  }
  ```

  ```js Usage theme={"system"}
  import { autocomplete } from "@algolia/autocomplete-js";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            header({ html }) {
              return htmlShim("<div>Products</div>", html);
            },
            item({ item, components, html }) {
              const template = [
                "<div><h2>",
                components.Highlight({
                  hit: item,
                  attribute: "name",
                }),
                "</h2><p>",
                item.price,
                "</p><div>",
              ];

              return htmlShim(template, html);
            },
          },
        },
      ];
    },
  });
  ```
</CodeGroup>

<Note>
  The documented shim assumes every even array entry is a template string, and every odd entry is a dynamic value.
  Change the shim if you need it to do something different.
</Note>

### Further optimizations

The provided `html` function works in the browser without any build step, with a negligible impact on memory and bundle size (\< 600 bytes).

<Warning>
  To ensure optimal performance,
  use [`babel-plugin-htm`](https://github.com/developit/htm/tree/master/packages/babel-plugin-htm) to compile HTML tagged templates.
  This plugin replaces `html` calls, so your code must expose a consistent parameter name to the compiler.
  Avoid destructuring directly in the function signature.
  Instead, either name the parameter and destructure it inside the function body,
  or pass the object as-is.
  The parameter name (for example, `params`) must be consistent across all templates.
</Warning>

```diff JavaScript icon=code theme={"system"}
autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
-         item({ item, html }) {
+         item(params) {
+           const { item, html } = params;

            return html`<div>${item.name}</div>`;
          },
        },
      },
    ];
  },
- render({ children, render, html }, root) {
+ render(params, root) {
+   const { children, render, html } = params;

    render(html`<div>${children}</div>`, root);
  },
});
```

Set up the Babel plugin.

```js .babelrc theme={"system"}
{
  "plugins": [
    [
      "htm",
      {
        "pragma": "params.createElement"
      }
    ]
  ]
}
```

<Note>
  If you're destructuring objects, ensure you also transpile it using [`@babel/preset-env`](https://babeljs.io/docs/en/babel-preset-env).
</Note>

## Return virtual nodes directly

You can return virtual nodes with JSX or `createElement`.

### With JSX

The JSX syntax compiles down to VNodes.
If you're using JSX in your project, **you can directly return JSX templates**.

```jsx JSX icon=code theme={"system"}
/** @jsx h */
import { h } from "preact";
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item }) {
            return <div>{item.name}</div>;
          },
        },
      },
    ];
  },
});
```

<Note>
  By default, Autocomplete uses [Preact 10](https://preactjs.com/guide/v10/whats-new/) to render templates.
  If you're using another virtual DOM implementation, you can [pass a custom `renderer`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#param-renderer).
</Note>

### With `createElement`

Each template function provides access to `createElement` and `Fragment` to create VNodes.

```js JavaScript icon=code theme={"system"}
import { autocomplete } from "@algolia/autocomplete-js";

autocomplete({
  // ...
  getSources() {
    return [
      {
        // ...
        templates: {
          item({ item, createElement, Fragment }) {
            return createElement(Fragment, {}, item.name);
          },
        },
      },
    ];
  },
});
```

<Note>
  By default, `createElement` and `Fragment` default to Preact's `preact.createElement` (or `h`) and `preact.Fragment`.
  If you're using another virtual DOM implementation, you can [replace them](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#param-renderer).
</Note>

## Render a header and footer

In addition to rendering items, you can customize what to display before and after the list of items using the [`header`](#param-templates-header) and [`footer`](#param-templates-footer) templates.

```js JavaScript icon=code theme={"system"}
autocomplete({
  // ...
  getSources({ query }) {
    return [
      {
        // ...
        templates: {
          header() {
            return "Suggestions";
          },
          item({ item }) {
            return `Result: ${item.name}`;
          },
          footer() {
            return "Footer";
          },
        },
      },
    ];
  },
});
```

## Components

Autocomplete exposes [`components`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#param-components) to all templates to share them everywhere in the instance.

<CodeGroup>
  ```js JavaScript theme={"system"}
  autocomplete({
    // ...
    getSources({ query }) {
      return [
        {
          getItems() {
            return [
              /* ... */
            ];
          },
          templates: {
            item({ item, components }) {
              return components.Highlight({ hit: item, attribute: "name" });
            },
          },
        },
      ];
    },
  });
  ```

  ```jsx JSX theme={"system"}
  autocomplete({
    // ...
    getSources({ query }) {
      return [
        {
          getItems() {
            return [
              /* ... */
            ];
          },
          templates: {
            item({ item, components }) {
              return <components.Highlight hit={item} attribute="name" />;
            },
          },
        },
      ];
    },
  });
  ```
</CodeGroup>

[Four components](https://github.com/algolia/autocomplete/tree/next/packages/autocomplete-js/src/components) are registered by default:

* [`Highlight`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#highlight) to highlight matches in Algolia results.
* [`Snippet`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#snippet) to snippet matches in Algolia results.
* [`ReverseHighlight`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#reversehighlight) to reverse highlight matches in Algolia results.
* [`ReverseSnippet`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#reversesnippet) to reverse highlight and snippet matches in Algolia results.

## Highlight and snippet

Templates expose a set of built-in [`components`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete#param-components) to handle highlighting and snippeting.
Use these components to highlight or snippet results from the [`getAlgoliaResults`](/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/getAlgoliaResults) function.

<CodeGroup>
  ```js JavaScript theme={"system"}
  autocomplete({
    // ...
    getSources({ query }) {
      return [
        {
          // ...
          templates: {
            item({ item, components, html }) {
              return html`<div>
                <img class="thumbnail" src="${item.image}" />
                <a href="${item.url}">
                  ${components.Highlight({
                    hit: item,
                    attribute: "name",
                    tagName: "em",
                  })}
                </a>
              </div>`;
            },
          },
        },
      ];
    },
  });
  ```

  ```jsx JSX theme={"system"}
  autocomplete({
    // ...
    getSources({ query }) {
      return [
        {
          // ...
          templates: {
            item({ item, components }) {
              return (
                <div>
                  <img className="thumbnail" src={item.image} />
                  <a href={item.url}>
                    <components.Highlight
                      hit={item}
                      attribute="name"
                      tagName="em"
                    />
                  </a>
                </div>
              );
            },
          },
        },
      ];
    },
  });
  ```
</CodeGroup>

## Render a no-results state

If there are no results, you might want to display a message to inform users or let them know what to do next.
Do this with the [`noResults`](#param-templates-no-results) template.

```js JavaScript icon=code theme={"system"}
autocomplete({
  // ...
  getSources({ query }) {
    return [
      {
        // ...
        templates: {
          // ...
          noResults() {
            return "No results.";
          },
        },
      },
    ];
  },
});
```

## Style items

Since you're fully controlling the rendered HTML, style it how you want using any class-based CSS library.
For example, if you're using [Bootstrap](https://getbootstrap.com/):

<CodeGroup>
  ```js JavaScript theme={"system"}
  import { autocomplete } from "@algolia/autocomplete-js";

  import "https://cdn.jsdelivr.net/npm/bootstrap@latest/dist/css/bootstrap.min.css";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            item({ item, html }) {
              return html`<div class="list-group-item-action">${item.name}</div>`;
            },
          },
        },
      ];
    },
  });
  ```

  ```jsx JSX theme={"system"}
  /** @jsx h */
  import { h } from "preact";
  import { autocomplete } from "@algolia/autocomplete-js";

  import "https://cdn.jsdelivr.net/npm/bootstrap@latest/dist/css/bootstrap.min.css";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            item({ item }) {
              return <div className="list-group-item-action">{item.name}</div>;
            },
          },
        },
      ];
    },
  });
  ```
</CodeGroup>

Or [Tailwind CSS](https://tailwindcss.com/):

<CodeGroup>
  ```js JavaScript theme={"system"}
  import { autocomplete } from "@algolia/autocomplete-js";

  import "https://unpkg.com/tailwindcss@latest/dist/tailwind.min.css";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            item({ item, html }) {
              return html`<div
                class="py-2 px-4 rounded-sm border border-gray-200"
              >
                ${item.name}
              </div>`;
            },
          },
        },
      ];
    },
  });
  ```

  ```jsx JSX theme={"system"}
  /** @jsx h */
  import { h } from "preact";
  import { autocomplete } from "@algolia/autocomplete-js";

  import "https://unpkg.com/tailwindcss@latest/dist/tailwind.min.css";

  autocomplete({
    // ...
    getSources() {
      return [
        {
          // ...
          templates: {
            item({ item }) {
              return (
                <div className="py-2 px-4 rounded-sm border border-gray-200">
                  {item.name}
                </div>
              );
            },
          },
        },
      ];
    },
  });
  ```
</CodeGroup>

## Reference

<ParamField body="templates" type="AutocompleteTemplates">
  A set of templates to customize how items are displayed.
  You can also provide templates for header and footer elements around the list of items.

  You must define `templates` within your [sources](/doc/ui-libraries/autocomplete/core-concepts/sources).

  <Expandable defaultOpen>
    <ParamField body="templates.header" type="function">
      ```ts Type definition theme={"system"}
      (params: {
        state: AutocompleteState<TItem>;
        source: AutocompleteSource<TItem>;
        items: TItem[];
        createElement: Pragma;
        Fragment: PragmaFrag;
        components: AutocompleteComponents;
      }) => VNode | string;
      ```

      A function that returns the template for the header (before the list of items).
    </ParamField>

    <ParamField body="templates.item" type="function">
      ```ts Type definition theme={"system"}
      (params: {
        item: TItem;
        state: AutocompleteState<TItem>;
        createElement: Pragma;
        Fragment: PragmaFrag;
        components: AutocompleteComponents;
      }) => VNode | string;
      ```

      A function that returns the template for each item of the source.
    </ParamField>

    <ParamField body="templates.footer" type="function">
      ```ts Type definition theme={"system"}
      (params: {
        state: AutocompleteState<TItem>;
        source: AutocompleteSource<TItem>;
        items: TItem[];
        createElement: Pragma;
        Fragment: PragmaFrag;
        components: AutocompleteComponents;
      }) => VNode | string;
      ```

      A function that returns the template for the footer (after the list of items).
    </ParamField>

    <ParamField body="templates.noResults" type="function">
      ```ts Type definition theme={"system"}
      (params: {
        state: AutocompleteState<TItem>;
        source: AutocompleteSource<TItem>;
        createElement: Pragma;
        Fragment: PragmaFrag;
        components: AutocompleteComponents;
      }) => VNode | string;
      ```

      A function that returns the template for when there are no items.
    </ParamField>
  </Expandable>
</ParamField>
