Skip to content

Custom Templates

Examples of custom item rendering using the renderItem function.

User Profiles

javascript
autocomplete.renderItem = (user, html, { highlighted }) => html`
  <div class="user-profile ${highlighted ? 'highlighted' : ''}">
    <img
      class="avatar"
      src=${user.avatar || '/default-avatar.png'}
      alt=""
    />
    <div class="user-info">
      <span class="name">${user.name}</span>
      <span class="email">${user.email}</span>
      ${user.role && html`<span class="role">${user.role}</span>`}
    </div>
    ${user.online && html`<span class="status online">●</span>`}
  </div>
`
css
.user-profile {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 12px;
}

.user-profile.highlighted {
  background: var(--pac-highlight-bg);
}

.user-profile .avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  object-fit: cover;
}

.user-profile .user-info {
  flex: 1;
  display: flex;
  flex-direction: column;
}

.user-profile .name {
  font-weight: 600;
  color: var(--pac-text-color);
}

.user-profile .email {
  font-size: 12px;
  color: var(--pac-placeholder-color);
}

.user-profile .role {
  font-size: 11px;
  color: #3b82f6;
  background: #eff6ff;
  padding: 2px 6px;
  border-radius: 4px;
  width: fit-content;
  margin-top: 4px;
}

.user-profile .status.online {
  color: #22c55e;
  font-size: 10px;
}

Product Cards

javascript
autocomplete.renderItem = (product, html, { highlighted }) => html`
  <div class="product-card ${highlighted ? 'highlighted' : ''}">
    <img
      class="product-image"
      src=${product.thumbnail}
      alt=${product.name}
    />
    <div class="product-details">
      <span class="product-name">${product.name}</span>
      <span class="product-category">${product.category}</span>
      <div class="product-footer">
        <span class="product-price">$${product.price.toFixed(2)}</span>
        ${product.inStock
          ? html`<span class="stock in-stock">In Stock</span>`
          : html`<span class="stock out-of-stock">Out of Stock</span>`
        }
      </div>
    </div>
  </div>
`
javascript
autocomplete.renderItem = (location, html, { highlighted }) => html`
  <div class="location-item ${highlighted ? 'highlighted' : ''}">
    <div class="location-icon">
      ${location.type === 'city' ? '🏙️' : location.type === 'airport' ? '✈️' : '📍'}
    </div>
    <div class="location-details">
      <span class="location-name">${location.name}</span>
      <span class="location-meta">
        ${location.country}
        ${location.code && html` · <code>${location.code}</code>`}
      </span>
    </div>
  </div>
`

Search Results with Highlighting

javascript
// Highlight matching text
function highlightMatch(text, query) {
  if (!query) return text
  const regex = new RegExp(`(${escapeRegex(query)})`, 'gi')
  const parts = text.split(regex)
  return parts.map(part =>
    part.toLowerCase() === query.toLowerCase()
      ? html`<mark>${part}</mark>`
      : part
  )
}

function escapeRegex(string) {
  return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

let currentQuery = ''

// Track query changes
autocomplete.addEventListener('pac:items-loaded', (e) => {
  currentQuery = e.detail.query
})

autocomplete.renderItem = (item, html, { highlighted }) => html`
  <div class="search-result ${highlighted ? 'highlighted' : ''}">
    <span class="result-title">${highlightMatch(item.title, currentQuery)}</span>
    <span class="result-snippet">${item.snippet}</span>
    <span class="result-url">${item.url}</span>
  </div>
`

Tags/Chips Style

javascript
autocomplete.renderItem = (tag, html, { highlighted }) => html`
  <div class="tag-item ${highlighted ? 'highlighted' : ''}">
    <span
      class="tag-color"
      style="background-color: ${tag.color}"
    ></span>
    <span class="tag-name">${tag.name}</span>
    <span class="tag-count">${tag.count}</span>
  </div>
`
css
.tag-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 12px;
}

.tag-item.highlighted {
  background: var(--pac-highlight-bg);
}

.tag-item .tag-color {
  width: 12px;
  height: 12px;
  border-radius: 3px;
}

.tag-item .tag-name {
  flex: 1;
  font-weight: 500;
}

.tag-item .tag-count {
  font-size: 12px;
  color: var(--pac-placeholder-color);
  background: var(--pac-border-color);
  padding: 2px 8px;
  border-radius: 10px;
}

Command Palette

javascript
autocomplete.renderItem = (command, html, { highlighted }) => html`
  <div class="command-item ${highlighted ? 'highlighted' : ''}">
    <span class="command-icon">${command.icon}</span>
    <div class="command-info">
      <span class="command-name">${command.name}</span>
      <span class="command-description">${command.description}</span>
    </div>
    ${command.shortcut && html`
      <kbd class="command-shortcut">${command.shortcut}</kbd>
    `}
  </div>
`
css
.command-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
}

.command-item.highlighted {
  background: var(--pac-highlight-bg);
}

.command-item .command-icon {
  font-size: 18px;
  width: 24px;
  text-align: center;
}

.command-item .command-info {
  flex: 1;
}

.command-item .command-name {
  display: block;
  font-weight: 500;
}

.command-item .command-description {
  font-size: 12px;
  color: var(--pac-placeholder-color);
}

.command-item .command-shortcut {
  font-family: monospace;
  font-size: 11px;
  padding: 2px 6px;
  background: var(--pac-border-color);
  border-radius: 4px;
}