Recherche

La recherche est une fenêtre modale par-dessus la page courante : un bouton dans l’en-tête ouvre un panneau propulsé par Pagefind, avec un seul champ et une liste de résultats en direct. L’index est construit au déploiement à partir du HTML rendu; la recherche ne coûte donc ni serveur ni tiers — le navigateur télécharge des fragments d’index à mesure qu’on tape.

Le bouton de recherche dans l’en-tête de cette page est le déclencheur en direct — appuyez dessus, ou sur ⌘K, et la fenêtre modale s’ouvre par-dessus cette page.

Quand l’utiliser#

  • Recherche dans tout le site depuis n’importe quelle page : le déclencheur vit dans l’en-tête et la fenêtre modale est rendue une fois par page par le gabarit de base
  • Chaque site cherche dans son propre index — npm run index exécute Pagefind séparément sur la sortie du site principal et celle du site de marque
  • Dans la section des liens, la requête est filtrée à cette section : la liste de lecture se cherche elle-même
  • Pas un filtre de données : pour restreindre un tableau ou une liste sur une page, utilisez plutôt le composant rangée de filtres

Implémentation#

{{ partial "search.html" . }}       {{/* déclencheur, rendu par header.html */}}
{{ partial "search-modal.html" . }} {{/* fenêtre modale, rendue une fois par baseof.html */}}
<button id="search-trigger" class="search-trigger" type="button" aria-keyshortcuts="Control+K Meta+K" aria-haspopup="dialog" aria-controls="search-modal">
  <svg class="search-trigger-icon" viewBox="0 0 24 24" aria-hidden="true">…</svg>
  <span>Rechercher</span>
  <kbd>⌘K</kbd>
</button>

<div id="search-modal" class="search-modal hidden" role="dialog" aria-modal="true" aria-label="Rechercher dans le site">
  <div id="search-backdrop" class="search-backdrop"></div>
  <div class="search-panel">
    <div class="search-field">
      <input id="search-input" type="search" autocomplete="off" placeholder="Rechercher dans le site" aria-label="Rechercher dans le site" />
      <kbd>Esc</kbd>
    </div>
    <div id="search-results" class="search-results">…</div>
  </div>
</div>

Le câblage vit dans assets/js/site.js. À l’ouverture — un clic sur le déclencheur, ou ⌘K / Ctrl+K n’importe où —, l’élément qui a le focus est mémorisé, la fenêtre modale apparaît, le défilement de la page se verrouille, le champ se vide et reçoit le focus; le module Pagefind est importé paresseusement à la première ouverture. La saisie est temporisée à 180 ms, chaque requête affiche jusqu’à huit résultats sous forme de liens, et Échap, un clic sur le voile ou le suivi d’un résultat ferme la fenêtre. La fermeture renvoie le focus à l’élément qui l’avait avant l’ouverture — le bouton déclencheur dans le cas ordinaire — et un écouteur de Tab sur la fenêtre modale piège le focus entre le premier et le dernier élément pouvant recevoir le focus tant qu’elle reste ouverte, parce que aria-modal="true" est une promesse faite à la technologie d’assistance, pas un mécanisme d’application.

ÉlémentRôle
#search-triggerBouton de l’en-tête qui ouvre la fenêtre modale
#search-modalLa boîte de dialogue elle-même; masquée par classe jusqu’à l’ouverture
#search-backdropVoile derrière le panneau; un clic dessus ferme la fenêtre
#search-inputLe champ de requête; le focus s’y pose à l’ouverture
#search-resultsLes liens de résultats et les messages d’attente, d’absence et d’erreur

Le partial du déclencheur est layouts/partials/search.html, rendu dans l’en-tête, et la fenêtre modale est layouts/partials/search-modal.html, rendue une fois par layouts/_default/baseof.html. Toutes les chaînes sont localisées : les partials lisent directement les clés i18n, et le JavaScript reçoit ses messages par le bloc JSON app-config que le gabarit de base intègre. Pagefind se charge depuis params.pagefindPath et interroge l’index par site que npm run index construit après le rendu Hugo. Le style vient des règles .search-* dans assets/css/site.css.

Options#

OptionRôle
params.pagefindPathParamètre de site indiquant l’emplacement de Pagefind; /pagefind/pagefind.js par défaut
pagefind_excludeIndicateur de front matter qui retire data-pagefind-body et garde la page hors de l’index

Manifeste d’interface

Nature
Composant
Catégorie
Action
Statut
Implémenté
Implémentation
Partial:layouts/partials/search.htmllayouts/partials/search-modal.htmlCSS:assets/css/site.cssJavaScript:assets/js/site.jsi18n:searchShortsearchPlaceholdersearchUnavailablesearchErrorsearchNoResultsConfiguration:config/brand/hugo.yml

Accessibilité#

  • La fenêtre modale est un role="dialog" avec aria-modal="true" et un aria-label localisé (« Rechercher dans le site »), et le déclencheur est un <button type="button"> natif portant aria-keyshortcuts="Control+K Meta+K" : Entrée et Espace l’ouvrent, et l’indice ⌘K atteint les lecteurs d’écran en plus du <kbd> visible
  • Le focus se pose dans le champ de recherche dès l’ouverture et reste piégé dans la boîte de dialogue — Tab depuis le dernier élément pouvant recevoir le focus revient au premier, Maj+Tab depuis le premier revient au dernier — de sorte que rien derrière le voile n’est atteignable tant qu’elle est ouverte
  • Échap ferme la fenêtre depuis n’importe où dans le document, en accord avec l’indice visible Esc du champ; la fermeture renvoie le focus à l’élément qui l’a ouverte, pour qu’une personne au clavier reprenne exactement là où elle en était
  • Évitez de remplacer le déclencheur par un lien — le composant dépend de la sémantique du bouton; un lien casserait l’activation par Espace et annoncerait le mauvais rôle