La copie de texte (code de bienvenue, code promo, etc.) est une action de plus en plus fréquente.
Ce n'est pas bien compliqué à faire, mais il faut aussi que ce soit accessible à tous les utilisateurs.
Il se trouve qu'on ne peut pas toujours mettre un button standard qui respecte les interactions au clavier et il faut également gérer les potentielles erreurs, en plus des messages de confirmation.
Concernant les éléments permettant de copier du contenu, le plus simple est l'utilisation de button, mais on peut également utiliser des éléments capables de recevoir le role="button" qui sera géré par le script.
Les éléments acceptent 4 attributs :
-
data-clipboardou classe CSSclipboard(obligatoire)<button data-clipboard type="button"> Texte à copier </button> -
data-clipboard-messagemessage qui sera utilisé comme message de succès. Si absent, utilise une valeur par défaut dans le script.
Exemple :<button class="clipboard link-color" type="button" data-clipboard-message="Message d'information de succès"> Texte à copier </button> -
data-copymessage qui sera utilisé commetitledu bouton. Si absent, utilise une valeur par défaut dans le script.
Exemple :<button class="green font-weight-700" data-clipboard type="button" data-copy="Copier"> Texte à copier </button> -
data-targetcible un élément dans la page avec un sélecteur de classe ou identifiant. Si absent, utilise le contenu de l'élément lui-même.
Remplacement debuttonpar unspan.
Exemple :<span data-clipboard data-target="#target_id_element"> Copier le code SUMMER50 </span> <!-- plus loin dans le code --> <span class="sr-only" aria-hidden="true" id="target_id_element">SUMMER50</span>
Tous les attributs peuvent être combinés.
Javascript
Taille brute : 4,54 kilo-octets (~1,74 kilo-octets gzip)
;(() => {
'use strict';
// Récupère les traductions contextualisées selon la langue (via window.i18n), sinon utilise les valeurs par défaut
const i18n = window.i18n || {};
const defaultTranslations = {
copy_to_clipboard: "Copier le texte",
copy_to_clipboard_true: "C'est copié !",
copy_to_clipboard_empty: "Il n'y a rien à copier…",
copy_to_clipboard_false: "Votre navigateur ne prend pas en charge ce type de script."
};
// Fonction de récupération des traductions
function t(key) {
return i18n[key] || defaultTranslations[key];
}
// Namespace global Clipboard
window.Clipboard = {
// Copie le texte du nœud ciblé dans le presse-papier
copy(target) {
const text = (target.textContent || target.value || "").trim();
if (!text?.trim().length) return false;
// API moderne si disponible
if (navigator.clipboard?.writeText) {
return navigator.clipboard.writeText(text)
.then(() => true)
.catch(err => {
console.warn("Erreur navigateur.clipboard :", err);
return Clipboard.copyFallback(text);
});
}
// Fallback pour anciens navigateurs
return Clipboard.copyFallback(text);
}, // Méthode alternative de copie via textarea caché
copyFallback(text) {
const textarea = document.createElement("textarea");
textarea.value = text;
textarea.setAttribute("readonly", "");
// Normalement, vous devez bien avoir une classe sr-only ou du genre
textarea.classList.add('sr-only');
// sinon…
// textarea.style.position = "absolute";
// textarea.style.left = "-9999px";
document.body.appendChild(textarea);
const selection = window.getSelection();
const originalRange = selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
textarea.select();
let success = false;
try {
success = document.execCommand("copy");
} catch (err) {
console.warn("Erreur fallback execCommand :", err);
}
selection.removeAllRanges();
if (originalRange) selection.addRange(originalRange);
document.body.removeChild(textarea);
return success;
},
// Initialise les boutons qui déclenchent la copie
init(node = document) {
node.querySelectorAll(".clipboard, [data-clipboard]").forEach(button => {
if (!button.textContent.trim().length) {
button.setAttribute("title", button.getAttribute("data-copy") || t('copy_to_clipboard'));
}
button.hasAttribute('data-copy') && button.removeAttribute('data-copy');
// Accessibilité : rôle "button" pour les éléments non <button>
if (button.tagName !== "BUTTON") {
button.setAttribute("tabindex", "0");
button.setAttribute("role", "button");
button.addEventListener("keydown", function (e) {
// Active le clic clavier sur Espace ou Entrée
if (e.key === " " || e.key === "Enter") {
e.preventDefault();
this.click();
}
});
}
button.addEventListener("click", function () {
const target = !this.hasAttribute("data-target") ? this : document.querySelector(this.dataset.target);
if (!target || !target.textContent.trim().length) {
Clipboard.message(t('copy_to_clipboard_empty'), "alert", button);
return;
}
const success = Clipboard.copy(target);
(success instanceof Promise) ? success.then(ok => {
Clipboard.message(ok ? (this.getAttribute("data-clipboard-message") || t('copy_to_clipboard_true')) : t('copy_to_clipboard_false'), ok ? "success" : "error", button);
}) : Clipboard.message(success ? (this.getAttribute("data-clipboard-message") || t('copy_to_clipboard_true')) : t('copy_to_clipboard_false'), success ? "success" : "error", button);
});
});
}, // Affiche un message via snackBar ou alert()
message(text, type = "", opener) {
const validType = ["", "info", "success", "alert", "error"].includes(type) ? type : "";
typeof window.snackBar === "function" ? snackBar({
content: text,
css: validType,
position: 'top-center',
time: 1500,
width: '15.625rem',
modal: true,
opener: opener
}) : alert(text);
}
};
// Lance l'initialisation au chargement du DOM
document.addEventListener("DOMContentLoaded", () => Clipboard.init());
})();
Télécharger kortic-clipboard.js
That's all, Folks !