Un placeholder classique comme "Rechercher..." reste figé et n'inspire pas vraiment l'utilisateur. Comment suggérer de manière dynamique ce qu'il est possible de chercher ? Comment créer cette sensation de site "vivant" sans pour autant gêner l'expérience utilisateur ?

La réponse : une animation typewriter intelligente qui cycle entre différents termes de recherche, s'adapte aux interactions utilisateur et reste performante.

une animation typewriter intelligente qui cycle entre différents termes de recherche

L'Approche Technique

Pour créer une animation placeholder vraiment efficace, nous devons aller au-delà du simple effet visuel. L'objectif est de développer un système intelligent qui comprend le contexte utilisateur, s'adapte aux interactions en temps réel, et maintient des performances optimales même sur des appareils moins puissants.

Notre approche technique s'articule autour de trois fondements essentiels :

Animation fluide

Effet de frappe et d'effacement réaliste

Interaction intelligente

Pause pendant la saisie utilisateur

Performance optimisée

Gestion propre des timeouts et événements

Implémentation Complète

1. Le Cœur de l'Animation TypeScript

Créons notre moteur d'animation dans placeholder-animation.ts :

interface PlaceholderAnimationOptions {
  typingSpeed?: number;
  deletingSpeed?: number;
  pauseDuration?: number;
}

export function initPlaceholderAnimation(
  element: HTMLInputElement,
  terms: string[],
  options: PlaceholderAnimationOptions = {}
): void {
  if (!terms || terms.length === 0) return;

  const {
    typingSpeed = 100,
    deletingSpeed = 50,
    pauseDuration = 1000
  } = options;

  let currentTermIndex = 0;
  let currentCharIndex = 0;
  let isDeleting = false;
  let animationId: ReturnType<typeof setTimeout> | null = null;
  let isActive = true;

  function animate(): void {
    if (!isActive) return;

    const currentTerm = terms[currentTermIndex];

    if (!isDeleting) {
      // Typing phase: add one character
      element.placeholder = currentTerm.substring(0, currentCharIndex + 1);
      currentCharIndex++;

      if (currentCharIndex === currentTerm.length) {
        // Word complete, pause then start deleting
        animationId = setTimeout(() => {
          isDeleting = true;
          animate();
        }, pauseDuration);
        return;
      }
    } else {
      // Deleting phase: remove one character
      element.placeholder = currentTerm.substring(0, currentCharIndex);
      currentCharIndex--;

      if (currentCharIndex < 0) {
        // Deletion complete, move to next term
        isDeleting = false;
        currentTermIndex = (currentTermIndex + 1) % terms.length;
        currentCharIndex = 0;
      }
    }

    const speed = isDeleting ? deletingSpeed : typingSpeed;
    animationId = setTimeout(animate, speed);
  }

  // Stop animation on focus, clear placeholder
  function stopAnimation(): void {
    isActive = false;
    if (animationId) {
      clearTimeout(animationId);
      animationId = null;
    }
    element.placeholder = '';
  }

  // Restart animation on blur if input is empty
  function startAnimation(): void {
    if (element.value === '') {
      isActive = true;
      currentTermIndex = 0;
      currentCharIndex = 0;
      isDeleting = false;
      animate();
    }
  }

  element.addEventListener('focus', stopAnimation);
  element.addEventListener('blur', startAnimation);

  animate();
}

2. Auto-détection et Initialisation

Pour garantir une intégration transparente dans vos projets existants, nous développons un système d'auto-détection qui scanne automatiquement le DOM à la recherche de formulaires configurés pour l'animation. Cette approche élimine la nécessité d'initialiser manuellement chaque champ de recherche et rend la solution facilement maintenable même sur des sites complexes avec de multiples formulaires.

La fonction helper ci-dessous automatise entièrement le processus :

export function initPlaceholderAnimations(): void {
  const searchForms = document.querySelectorAll<HTMLFormElement>('[data-placeholder-terms]');

  searchForms.forEach(form => {
    const input = form.querySelector<HTMLInputElement>('input[type="search"]');
    const termsData = form.getAttribute('data-placeholder-terms');

    if (input && termsData) {
      try {
        const terms = JSON.parse(termsData);
        if (Array.isArray(terms)) {
          initPlaceholderAnimation(input, terms);
        }
      } catch (error) {
        console.warn('Invalid placeholder terms data:', error);
      }
    }
  });
}

3. Intégration HTML Propre

L'un des atouts majeurs de cette solution est sa simplicité d'intégration. Plutôt que d'imposer une structure HTML complexe ou des classes CSS spécifiques, nous utilisons une approche basée sur les attributs data, garantissant une compatibilité maximale avec n'importe quel framework ou CMS.

Cette méthode respecte les standards web modernes et permet une séparation claire entre la logique JavaScript et le markup HTML. Voici comment l'implémenter dans vos templates :

<form class="search-form" data-placeholder-terms="<?php echo json_encode(['produits', 'services', 'documentation', 'support']); ?>">
  <input type="search"
         name="s"
         placeholder="Rechercher..."
         class="search-input">
  <button type="submit">Rechercher</button>
</form>

4. Activation Globale

Dans votre app.ts principal :

import { initPlaceholderAnimations } from './lib/placeholder-animation';

// Initialize animations when DOM is ready
initPlaceholderAnimations();

Les Détails qui Font la Différence

Timing Réaliste

  • Frappe : 100ms par caractère (ni trop rapide, ni trop lent)
  • Effacement : 50ms par caractère (plus rapide, comme un vrai backspace)
  • Pause : 1000ms entre les mots (laisse le temps de lire)

Interaction Intelligente

L'animation comprend quand l'utilisateur veut interagir :

  • Focus : animation stop, placeholder disparaît
  • Blur sur champ vide : animation reprend depuis le début
  • Blur sur champ rempli : aucune animation (logique)

Performance Sans Compromis

L'optimisation technique garantit une exécution fluide :

  • Nettoyage automatique des timeouts
  • Arrêt complet pendant les interactions
  • Aucune manipulation DOM inutile

Personnalisation Avancée

Adaptez l'animation à votre contexte :

// Animation plus lente et contemplative
initPlaceholderAnimation(input, terms, {
  typingSpeed: 150,
  deletingSpeed: 75,
  pauseDuration: 2500
});

// Animation rapide et dynamique
initPlaceholderAnimation(input, terms, {
  typingSpeed: 60,
  deletingSpeed: 30,
  pauseDuration: 800
});

En Production

Quelques bonnes pratiques pour le déploiement :

  1. Termes pertinents : Choisissez des mots qui reflètent vraiment votre contenu
  2. Longueur raisonnable : 3-5 termes suffisent pour éviter la lassitude
  3. Responsive : Testez sur mobile où le focus se comporte différemment
  4. Performance : L'animation se désactive automatiquement quand nécessaire
  5. Contenu dynamique : Dans le cas d'un site e-commerce, vous pourriez par exemple aller chercher les catégories ou les noms de produits directement depuis WooCommerce pour alimenter automatiquement la liste des termes suggérés :
function get_search_placeholder_terms() {
    $terms = [];

    // Get popular product categories
    $categories = get_terms([
        'taxonomy' => 'product_cat',
        'orderby' => 'count',
        'order' => 'DESC',
        'number' => 3,
        'hide_empty' => true
    ]);

    foreach ($categories as $category) {
        $terms[] = $category->name;
    }

    // Add featured products
    $products = wc_get_products([
        'limit' => 2,
        'orderby' => 'popularity',
        'status' => 'publish'
    ]);

    foreach ($products as $product) {
        $terms[] = $product->get_name();
    }

    return array_slice($terms, 0, 5); // Limit to 5 terms
}

Conclusion

Cette animation typewriter pour placeholder démontre qu'une micro-interaction bien pensée peut transformer radicalement l'expérience utilisateur. En alliant performance technique et design intelligent, nous créons une solution qui guide naturellement l'utilisateur tout en maintenant une fluidité d'interaction irréprochable.

L'approche développée ici illustre parfaitement comment les détails techniques minutieux et l'attention portée à l'expérience utilisateur convergent pour créer des interfaces web modernes et engageantes. Une simple animation de placeholder devient ainsi un véritable outil de communication avec l'utilisateur, suggérant subtilement les possibilités offertes par votre site.


Cet effet fonctionne particulièrement bien sur les sites e-commerce, portfolios et plateformes de contenu où guider la recherche utilisateur est crucial pour l'engagement.

Articles reliés

Retrouvez ci-dessous quelques articles qui pourraient vous intéresser.

21
jui
Octa : structure de thème WordPress ultra-moderne pour un développement rapide

Octa : structure de thème WordPress ultra-moderne pour un développement rapide

Octa est une structure de thème (starter theme) WordPress conçue pour les développeurs avancés en quête d’un workflow moderne. Présenté comme un thème WordPress « puissant » basé sur Laravel, Bedrock et Sage, Octa combine les outils du stack Roots (Bedrock, Sage 11, Acorn…) pour fournir un socle de développement complet.
Lire la suite
06
mar
Champ ACF en fonction de la profondeur du menu dans WordPress

Champ ACF en fonction de la profondeur du menu dans WordPress

ACF propose de pouvoir rajouter des champs personnalisés à un élément de menu, mais il ne propose pas de pouvoir l’assigner uniquement à un niveau de profondeur, nous allons découvrir comment le mettre en place simplement. Pour ce faire, nous allons rajouter un nouveau type de règle qui sera assigné au sous-niveau Formulaire, on lui…

Lire la suite
inRage - Pascal GAULT
© 2008-2021 - inRage SARL. Tous droits réservés.
Code open-source inrage.fr disponible sur Code open-source disponible sur Github
Demandez un devis
06 82 96 38 89
SIRET : 813 430 592 00010
R.C.S : La Rochelle 813 430 592

10-14 rue Jean Perrin,
17000 LA ROCHELLE