<span class="has-tooltip has-tooltip-button has-tooltip-bottom">
    <a href="#" class="rtds-tooltip-button" aria-describedby="tooltip-id">

        Tooltip link

    </a>
    <span class="rtds-tooltip is-centered" id="tooltip-id">Contenuto descrittivo del tooltip link</span>
</span>
<{{ wrapperTag | default('span') }} class="has-tooltip has-tooltip-button has-tooltip-bottom{% block classes %}{% if classes %} {{ classes }}{% endif %}{% endblock classes %}">
  <{% if href %}a href="{{ href }}"{% else %}button type="{% if buttonType %}{{ buttonType }}{% else %}button{% endif %}"{% endif %} class="rtds-tooltip-button{% block buttonClasses %}{% if buttonClasses %} {{ buttonClasses }}{% endif %}{% endblock buttonClasses %}" 
  {% if iconOnly %}aria-labelledby{% else %}aria-describedby{% endif %}="{{ id }}">
    {% block buttonContent %}
      {% if iconOnly %}
        {% render "@icon", icon.context, true %}
      {% else %}
        {{ label | safe }}
      {% endif %}
    {% endblock buttonContent %}
  </{% if href %}a{% else %}button{% endif %}>
  <span class="rtds-tooltip is-centered" id="{{ id }}">{{ content | safe }}</span>
</{{ wrapperTag | default('span') }}>
{
  "label": "Tooltip link",
  "content": "Contenuto descrittivo del tooltip link",
  "id": "tooltip-id",
  "wrapperTag": "span",
  "classes": "",
  "buttonClasses": "",
  "href": "#",
  "buttonType": "button"
}
  • Content:
    .has-tooltip {
        position: relative;
    }
    .has-tooltip-button {
        height: -moz-min-content;
        height: min-content;
        width: -moz-max-content;
        width: max-content;
        background-color: transparent;
        padding: var(--spacing-0);
        display: flex;
    }
    .rtds-tooltip {
            --_tooltip-padding-inline: 1.5ch;
            --_tooltip-padding-block: 0.75ch;
            --_toolip-triangle-size: 0.5rem;
        
            --tooltip-wrapper-width: var(--wrapper-width);
        
            --_tooltip-bottom-tip: conic-gradient(
                    from -30deg at bottom,
                    rgba(0, 0, 0, 0),
                    #000 1deg 60deg,
                    rgba(0, 0, 0, 0) 61deg
                )
                bottom / 100% 50% no-repeat;
            --_tooltip-top-tip: conic-gradient(from 150deg at top, rgba(0, 0, 0, 0), #000 1deg 60deg, rgba(0, 0, 0, 0) 61deg) top / 100% 50% no-repeat;
        
            --_tooltip-z-index: var(--tooltip-z-index, 1);
        
            --isRTL: -1;
        
            opacity: 0;
            visibility: hidden;
            inline-size: -moz-max-content;
            inline-size: max-content;
            max-inline-size: 25ch;
    
            transform: translateX(var(--_tooltip-x, 0)) translateY(var(--_tooltip-y, 0));
            transition: opacity 0.2s ease, transform 0.2s ease;
        
            pointer-events: none;
            -webkit-user-select: none;
            -moz-user-select: none;
                 user-select: none;
            position: absolute;
            z-index: var(--_tooltip-z-index);
            font-size: var(--fontsize-text-sm);
            font-weight: 500;
            color: var(--color-content-inverse);
            background-color: var(--color-background-07);
        border-radius: 0.375rem;
        --tw-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
        --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);
        box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
        line-height: 1;
        }
    .rtds-tooltip::after {
            content: "";
            background: var(--_tooltip-bg);
            position: absolute;
            z-index: -1;
            inset: 0;
            -webkit-mask: var(--_tip);
                    mask: var(--_tip);
            background-color: var(--color-background-07);
        }
    .rtds-tooltip-button:is(:hover, :active) + .rtds-tooltip,
        .is-visible .rtds-tooltip-button + .rtds-tooltip {
            padding: var(--_tooltip-padding-block) var(--_tooltip-padding-inline);
            opacity: 1;
            visibility: visible;
            pointer-events: auto; /* Abilita l'interazione con il mouse sul tooltip visibile */
            transition-delay: 200ms;
        }
    .has-tooltip-top .rtds-tooltip {
            bottom: calc(100% + var(--_tooltip-padding-block) + var(--_toolip-triangle-size));
        }
    /* Posizionamento centrato esplicito */
    .has-tooltip-top .rtds-tooltip.is-centered {
            left: 50%;
            --_tooltip-x: calc(50% * var(--isRTL));
        }
    .has-tooltip-top .rtds-tooltip::after {
            --_tip: var(--_tooltip-bottom-tip);
            bottom: calc(var(--_toolip-triangle-size) * -1);
            border-block-end: var(--_toolip-triangle-size) solid transparent;
        }
    .has-tooltip-top .rtds-tooltip.is-left-aligned {
            left: 0;
            --_tooltip-x: 0;
            text-align: left;
        }
    /*.has-tooltip-top .rtds-tooltip.is-left-aligned::after {
            right: calc(100% - (var(--tooltip-wrapper-width) * 1px));
        }*/
    .has-tooltip-top .rtds-tooltip.is-right-aligned {
            left: 100%;
            --_tooltip-x: -100%;
            text-align: left;
        }
    /*.has-tooltip-top .rtds-tooltip.is-right-aligned::after {
            left: calc(100% - (var(--tooltip-wrapper-width) * 1px));
        }*/
    .has-tooltip-bottom .rtds-tooltip {
            top: calc(100% + var(--_tooltip-padding-block) + var(--_toolip-triangle-size));
        }
    /* Posizionamento centrato esplicito */
    .has-tooltip-bottom .rtds-tooltip.is-centered {
            left: 50%;
            --_tooltip-x: calc(50% * var(--isRTL));
        }
    .has-tooltip-bottom .rtds-tooltip::after {
            --_tip: var(--_tooltip-top-tip);
            top: calc(var(--_toolip-triangle-size) * -1);
            border-block-start: var(--_toolip-triangle-size) solid transparent;
        }
    .has-tooltip-bottom .rtds-tooltip.is-left-aligned {
            left: 0;
            --_tooltip-x: 0;
            text-align: left;
        }
    .has-tooltip-top .rtds-tooltip.is-left-aligned::after,
        .has-tooltip-bottom .rtds-tooltip.is-left-aligned::after {
            /*right: var(--tooltip-wrapper-width);*/
            width: 0.5rem;
            left: 1rem;
        }
    .has-tooltip-bottom .rtds-tooltip.is-right-aligned {
            left: 100%;
            --_tooltip-x: -100%;
            text-align: left;
        }
    .has-tooltip-top .rtds-tooltip.is-right-aligned::after,
        .has-tooltip-bottom .rtds-tooltip.is-right-aligned::after {
            width: 0.5rem;
            right: 1rem;
            left: auto;
        }
    /* tooltip small */
    .rtds-tooltip--sm {
            --_tooltip-padding-block: 0.25rem;
            --_tooltip-padding-inline: 0.5rem;
            max-inline-size: 20ch;
            font-size: var(--fontsize-text-xs);
        }
    
  • URL: /components/raw/tooltip/tooltip.built.css
  • Filesystem Path: components/03-molecules/tooltip/tooltip.built.css
  • Size: 5 KB
  • Content:
    @layer components {
        .has-tooltip {
            @apply rtds-relative;
        }
    
        .has-tooltip-button {
            @apply rtds-flex rtds-w-max rtds-h-min rtds-bg-transparent rtds-p-0;
        }
    
        .rtds-tooltip {
            --_tooltip-padding-inline: 1.5ch;
            --_tooltip-padding-block: 0.75ch;
            --_toolip-triangle-size: 0.5rem;
        
            --tooltip-wrapper-width: var(--wrapper-width);
        
            --_tooltip-bottom-tip: conic-gradient(
                    from -30deg at bottom,
                    rgba(0, 0, 0, 0),
                    #000 1deg 60deg,
                    rgba(0, 0, 0, 0) 61deg
                )
                bottom / 100% 50% no-repeat;
            --_tooltip-top-tip: conic-gradient(from 150deg at top, rgba(0, 0, 0, 0), #000 1deg 60deg, rgba(0, 0, 0, 0) 61deg) top / 100% 50% no-repeat;
        
            --_tooltip-z-index: var(--tooltip-z-index, 1);
        
            --isRTL: -1;
        
            opacity: 0;
            visibility: hidden;
            inline-size: max-content;
            max-inline-size: 25ch;
    
            transform: translateX(var(--_tooltip-x, 0)) translateY(var(--_tooltip-y, 0));
            transition: opacity 0.2s ease, transform 0.2s ease;
        
            pointer-events: none;
            -webkit-user-select: none;
            user-select: none;
            position: absolute;
            z-index: var(--_tooltip-z-index);
        
        
            @apply rtds-font-medium rtds-background-07 rtds-rounded-md rtds-text-sm rtds-leading-none rtds-shadow-md rtds-content-inverse;
        }
    
        
        .rtds-tooltip::after {
            content: "";
            background: var(--_tooltip-bg);
            position: absolute;
            z-index: -1;
            inset: 0;
            mask: var(--_tip);
            @apply rtds-background-07;
        }
        
        .rtds-tooltip-button:is(:hover, :active) + .rtds-tooltip,
        .is-visible .rtds-tooltip-button + .rtds-tooltip {
            padding: var(--_tooltip-padding-block) var(--_tooltip-padding-inline);
            opacity: 1;
            visibility: visible;
            pointer-events: auto; /* Abilita l'interazione con il mouse sul tooltip visibile */
            transition-delay: 200ms;
        }
        
        .has-tooltip-top .rtds-tooltip {
            bottom: calc(100% + var(--_tooltip-padding-block) + var(--_toolip-triangle-size));
        }
    
        /* Posizionamento centrato esplicito */
        .has-tooltip-top .rtds-tooltip.is-centered {
            left: 50%;
            --_tooltip-x: calc(50% * var(--isRTL));
        }
    
        .has-tooltip-top .rtds-tooltip::after {
            --_tip: var(--_tooltip-bottom-tip);
            bottom: calc(var(--_toolip-triangle-size) * -1);
            border-block-end: var(--_toolip-triangle-size) solid transparent;
        }
    
        .has-tooltip-top .rtds-tooltip.is-left-aligned {
            left: 0;
            --_tooltip-x: 0;
            text-align: left;
        }
    
       /*.has-tooltip-top .rtds-tooltip.is-left-aligned::after {
            right: calc(100% - (var(--tooltip-wrapper-width) * 1px));
        }*/
    
        .has-tooltip-top .rtds-tooltip.is-right-aligned {
            left: 100%;
            --_tooltip-x: -100%;
            text-align: left;
        }
    
       /*.has-tooltip-top .rtds-tooltip.is-right-aligned::after {
            left: calc(100% - (var(--tooltip-wrapper-width) * 1px));
        }*/
        
        .has-tooltip-bottom .rtds-tooltip {
            top: calc(100% + var(--_tooltip-padding-block) + var(--_toolip-triangle-size));
        }
    
        /* Posizionamento centrato esplicito */
        .has-tooltip-bottom .rtds-tooltip.is-centered {
            left: 50%;
            --_tooltip-x: calc(50% * var(--isRTL));
        } 
    
        .has-tooltip-bottom .rtds-tooltip::after {
            --_tip: var(--_tooltip-top-tip);
            top: calc(var(--_toolip-triangle-size) * -1);
            border-block-start: var(--_toolip-triangle-size) solid transparent;
        }
    
        .has-tooltip-bottom .rtds-tooltip.is-left-aligned {
            left: 0;
            --_tooltip-x: 0;
            text-align: left;
        }
    
        .has-tooltip-top .rtds-tooltip.is-left-aligned::after,
        .has-tooltip-bottom .rtds-tooltip.is-left-aligned::after {
            /*right: var(--tooltip-wrapper-width);*/
            width: 0.5rem;
            left: 1rem;
        }
    
        .has-tooltip-bottom .rtds-tooltip.is-right-aligned {
            left: 100%;
            --_tooltip-x: -100%;
            text-align: left;
        }
    
        .has-tooltip-top .rtds-tooltip.is-right-aligned::after,
        .has-tooltip-bottom .rtds-tooltip.is-right-aligned::after {
            width: 0.5rem;
            right: 1rem;
            left: auto;
        }
    
        /* tooltip small */
        .rtds-tooltip--sm {
            --_tooltip-padding-block: 0.25rem;
            --_tooltip-padding-inline: 0.5rem;
            max-inline-size: 20ch;
            @apply rtds-text-xs;
        }
        
    }
  • URL: /components/raw/tooltip/tooltip.css
  • Filesystem Path: components/03-molecules/tooltip/tooltip.css
  • Size: 4.6 KB
  • Content:
    window.addEventListener('load', function() {
    // Verifica se esistono elementi con classe .has-tooltip
    const tooltipElements = document.querySelectorAll('.has-tooltip');
    if (tooltipElements.length > 0) {
        // TOOLTIP
        
        // Funzione globale per chiudere tutti i tooltip
        function closeAllTooltips(exceptElement = null) {
            tooltipElements.forEach(function(wrapper) {
                if (wrapper !== exceptElement && wrapper.classList.contains('is-visible')) {
                    const tooltip = wrapper.querySelector('.rtds-tooltip');
                    wrapper.classList.remove('is-visible');
                    // Reset dello stato click attivo
                    wrapper.setAttribute('data-click-active', 'false');
                    // Reset alle classi di default quando nascosto
                    tooltip.classList.remove('is-left-aligned', 'is-right-aligned');
                    if (!tooltip.classList.contains('is-centered')) {
                        tooltip.classList.add('is-centered');
                    }
                    wrapper.setAttribute('data-positioned', 'false');
                }
            });
        }
        tooltipElements.forEach(function (tooltipWrapper) {
            const triggerButton = tooltipWrapper.querySelector('.rtds-tooltip-button');
            const tooltip = tooltipWrapper.querySelector('.rtds-tooltip');
            let isClickActive = false;
            let isPositioned = false; // Flag per evitare ricalcoli inutili
    
            function handleTooltipPosition() {
                // Se già posizionato, non ricalcolare a meno che non sia resize
                if (isPositioned && arguments[0] !== 'resize') {
                    return;
                }
                
                // Controlla anche il data attribute per casi come ESC
                if (tooltipWrapper.getAttribute('data-positioned') === 'true' && arguments[0] !== 'resize') {
                    isPositioned = true;
                    return;
                }
                
                // Reset solo delle classi di allineamento speciali, mantieni is-centered per i calcoli
                tooltip.classList.remove('is-left-aligned', 'is-right-aligned');
                // Assicurati che abbia is-centered per i calcoli corretti
                if (!tooltip.classList.contains('is-centered')) {
                    tooltip.classList.add('is-centered');
                }
                
                // Rendi il tooltip temporaneamente visibile per il calcolo ma con opacity 0
                const wasVisible = tooltipWrapper.classList.contains('is-visible');
                if (!wasVisible) {
                    tooltip.style.visibility = 'visible';
                    tooltip.style.opacity = '0';
                    tooltip.style.padding = 'var(--_tooltip-padding-block) var(--_tooltip-padding-inline)';
                }
                
                requestAnimationFrame(() => {
                    var ww = window.innerWidth;
                    var rect = tooltip.getBoundingClientRect();
                    var tl = rect.left;
                    var tw = tooltip.offsetWidth;
                    var tooltipWrapperWidth = tooltipWrapper.offsetWidth;
                    var tr = tl + tw;
    
                    if (tl < 10) {
                        tooltip.style.setProperty('--wrapper-width', tooltipWrapperWidth + 'px');
                        tooltip.classList.remove('is-centered');
                        tooltip.classList.add('is-left-aligned');
                    } else if (tr > (ww - 10)) {
                        tooltip.style.setProperty('--wrapper-width', tooltipWrapperWidth + 'px');
                        tooltip.classList.remove('is-centered');
                        tooltip.classList.add('is-right-aligned');
                    } else {
                        // Caso default: tooltip centrato - mantiene is-centered già presente
                        // Non fa nulla, is-centered rimane applicata
                    }
                    
                    // Ripristina lo stato originale se il tooltip non era visibile
                    if (!wasVisible) {
                        tooltip.style.visibility = '';
                        tooltip.style.opacity = '';
                        tooltip.style.padding = '';
                    }
                    
                    // Marca come posizionato
                    isPositioned = true;
                    tooltipWrapper.setAttribute('data-positioned', 'true');
                });
            }
    
            // Il posizionamento viene ora calcolato dinamicamente quando serve
    
            // Gestione resize della finestra - ricalcola sempre e resetta il flag
            window.addEventListener('resize', function() {
                isPositioned = false; // Resetta il flag per forzare il ricalcolo
                tooltipWrapper.setAttribute('data-positioned', 'false');
                if (tooltipWrapper.classList.contains('is-visible')) {
                    handleTooltipPosition('resize');
                }
            });
    
            // Gestione click sul bottone
            triggerButton.addEventListener('click', function (e) {
                isClickActive = true;
                tooltipWrapper.setAttribute('data-click-active', 'true');
                // Chiudi tutti gli altri tooltip prima di mostrare questo
                closeAllTooltips(tooltipWrapper);
                // Pre-calcola la posizione PRIMA di rendere visibile il tooltip
                handleTooltipPosition();
                // Ora rendi visibile il tooltip con la posizione già corretta
                tooltipWrapper.classList.add('is-visible');
            });
    
            // Gestione hover del mouse con timeout per permettere il passaggio tra trigger e tooltip
            let hoverTimeout;
            
            function showTooltip() {
                // Sincronizza lo stato locale con il data attribute
                const clickActiveAttr = tooltipWrapper.getAttribute('data-click-active');
                if (clickActiveAttr === 'false') {
                    isClickActive = false;
                }
                
                if (!isClickActive) {
                    clearTimeout(hoverTimeout);
                    
                    // Apertura immediata - rimozione del delay
                    // Chiudi tutti gli altri tooltip prima di mostrare questo
                    closeAllTooltips(tooltipWrapper);
                    // Pre-calcola la posizione PRIMA di rendere visibile il tooltip
                    handleTooltipPosition();
                    // Ora rendi visibile il tooltip con la posizione già corretta
                    tooltipWrapper.classList.add('is-visible');
                }
            }
            
            function hideTooltip() {
                // Sincronizza lo stato locale con il data attribute
                const clickActiveAttr = tooltipWrapper.getAttribute('data-click-active');
                if (clickActiveAttr === 'false') {
                    isClickActive = false;
                }
                
                if (!isClickActive) {
                    hoverTimeout = setTimeout(() => {
                        tooltipWrapper.classList.remove('is-visible');
                        // Reset alle classi di default quando nascosto per evitare stati inconsistenti
                        tooltip.classList.remove('is-left-aligned', 'is-right-aligned');
                        if (!tooltip.classList.contains('is-centered')) {
                            tooltip.classList.add('is-centered');
                        }
                        // Reset del flag per permettere il ricalcolo al prossimo hover
                        isPositioned = false;
                        tooltipWrapper.setAttribute('data-positioned', 'false');
                    }, 1000); // Delay di 1 secondo per la chiusura
                }
            }
    
            // Eventi hover sul trigger
            triggerButton.addEventListener('mouseenter', showTooltip);
            triggerButton.addEventListener('mouseleave', hideTooltip);
            
            // Eventi hover sul tooltip stesso
            tooltip.addEventListener('mouseenter', showTooltip);
            tooltip.addEventListener('mouseleave', hideTooltip);
    
            // Gestione click fuori dal tooltip
            document.addEventListener('click', function(e) {
                if (isClickActive && !tooltipWrapper.contains(e.target)) {
                    isClickActive = false;
                    tooltipWrapper.setAttribute('data-click-active', 'false');
                    tooltipWrapper.classList.remove('is-visible');
                    // Reset alle classi di default quando nascosto
                    tooltip.classList.remove('is-left-aligned', 'is-right-aligned');
                    if (!tooltip.classList.contains('is-centered')) {
                        tooltip.classList.add('is-centered');
                    }
                    // Reset del flag per permettere il ricalcolo al prossimo hover
                    isPositioned = false;
                    tooltipWrapper.setAttribute('data-positioned', 'false');
                }
            });
    
            // Gestione focus con tastiera (Enter)
            triggerButton.addEventListener('keydown', function (e) {
                if (e.key === 'Enter') {
                    // Chiudi tutti gli altri tooltip prima di mostrare questo
                    closeAllTooltips(tooltipWrapper);
                    // Pre-calcola la posizione PRIMA di rendere visibile il tooltip
                    handleTooltipPosition();
                    // Ora rendi visibile il tooltip con la posizione già corretta
                    tooltipWrapper.classList.add('is-visible');
                }
            });
    
            // Gestione focus generico
            triggerButton.addEventListener('focusin', function (e) {
                // Apertura immediata anche per focus
                // Chiudi tutti gli altri tooltip prima di mostrare questo
                closeAllTooltips(tooltipWrapper);
                // Pre-calcola la posizione PRIMA di rendere visibile il tooltip
                handleTooltipPosition();
                // Ora rendi visibile il tooltip con la posizione già corretta
                tooltipWrapper.classList.add('is-visible');
            });
    
            // Gestione perdita focus
            triggerButton.addEventListener('focusout', function (e) {
                // Verifichiamo che il nuovo elemento di focus non sia all'interno del tooltip wrapper
                if (!tooltipWrapper.contains(e.relatedTarget)) {
                    tooltipWrapper.classList.remove('is-visible');
                    // Reset alle classi di default quando nascosto
                    tooltip.classList.remove('is-left-aligned', 'is-right-aligned');
                    if (!tooltip.classList.contains('is-centered')) {
                        tooltip.classList.add('is-centered');
                    }
                    // Reset del flag per permettere il ricalcolo al prossimo hover
                    isPositioned = false;
                    tooltipWrapper.setAttribute('data-positioned', 'false');
                }
            });
        });
    
        // Gestione tasto ESC
        document.addEventListener('keydown', function (e) {
            if (e.key === "Escape") {
                // Troviamo il tooltip attualmente attivo
                const activeTooltipWrapper = document.querySelector('.has-tooltip.is-visible');
                if (activeTooltipWrapper) {
                    const activeTooltip = activeTooltipWrapper.querySelector('.rtds-tooltip');
                    activeTooltipWrapper.classList.remove('is-visible');
                    // Reset alle classi di default quando nascosto
                    activeTooltip.classList.remove('is-left-aligned', 'is-right-aligned');
                    if (!activeTooltip.classList.contains('is-centered')) {
                        activeTooltip.classList.add('is-centered');
                    }
                    // Reset del flag per permettere il ricalcolo al prossimo hover
                    activeTooltipWrapper.setAttribute('data-positioned', 'false');
                    // Manteniamo il focus sul bottone trigger
                    activeTooltipWrapper.querySelector('.rtds-tooltip-button').focus();
                }
            }
        });
    }
    }); // end window.load
    
  • URL: /components/raw/tooltip/tooltip.js
  • Filesystem Path: components/03-molecules/tooltip/tooltip.js
  • Size: 11.7 KB

Tooltip

Componente tooltip accessibile che simula l’attributo title con miglioramenti significativi per l’accessibilità e l’usabilità.

Il tooltip può essere usato come:

  • Etichetta testuale primaria per button o link con icone (nome accessibile ed etichetta testuale visuale) — usa aria-labelledby="{idTooltip}"
  • Etichetta testuale secondaria per button o link (informazione descrittiva aggiuntiva, assimilabile all’attributo title) — usa aria-describedby="{idTooltip}"

Comportamento

Il componente è renderizzato come elemento wrapper (default <span>) contenente:

  • <button type="button"> o <a> — trigger del tooltip
  • <span class="rtds-tooltip"> — contenuto del tooltip, sempre presente nel DOM ma visibile solo all’interazione

Il trigger usa aria-labelledby puntato all’ID del tooltip quando il tooltip è il nome accessibile del trigger (es. pulsante icona-only), o aria-describedby quando è un’informazione descrittiva aggiuntiva.


Varianti

Varianti di Stile

  • default: Tooltip con button con icona come trigger — il tooltip ha funzione di etichetta testuale primaria (nome accessibile), usa aria-labelledby
  • title: Tooltip con funzione di title — etichetta testuale secondaria (informazione descrittiva aggiuntiva), usa aria-describedby
  • link: Tooltip con link come trigger

Parametri di configurazione

Contesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context .config.yml usati durante lo sviluppo nella libreria. Non descrive attributi HTML o proprietà da usare nei temi, CMS o ambienti di implementazione: per quello, fare riferimento alla sezione Esempi di utilizzo.

Parametri Base

  • label (stringa, obbligatorio): Testo del trigger (button/link)
  • content (stringa, obbligatorio): Contenuto del tooltip
  • id (stringa, obbligatorio): ID univoco per l’attributo aria-describedby o aria-labelledby

Parametri di Struttura

  • wrapperTag (stringa, opzionale): Tag del wrapper (default: “span”)
  • classes (stringa, opzionale): Classi CSS aggiuntive per il wrapper
  • buttonClasses (stringa, opzionale): Classi CSS aggiuntive per il trigger
  • href (stringa, opzionale): URL per il trigger link
  • buttonType (stringa, opzionale): Tipo del button se non è un link (default: “button”)

Accessibilità

WCAG 2.1

Livello AA — criteri pertinenti:

  • 1.3.1 Informazioni e correlazioni — il tooltip è collegato al trigger tramite aria-labelledby o aria-describedby in base al caso d’uso
  • 1.4.13 Contenuto al passaggio del puntatore o del focus — il tooltip è persistente (rimane visibile al click) e chiudibile (tramite Escape)
  • 4.1.2 Nome, ruolo, valore — il trigger usa aria-labelledby (quando il tooltip è il nome accessibile) o aria-describedby (quando è una descrizione aggiuntiva)

Struttura e semantica

  • <span> (o altro elemento wrapper) — contenitore di trigger e tooltip; non ha semantica propria
  • <button type="button"> — ruolo implicito button; attivabile con Enter e Space; usare per tooltip su elementi non navigabili
  • <a> — ruolo implicito link; attivabile con Enter; usare quando il trigger è un link
  • <span class="rtds-tooltip" role="tooltip"> — contenuto del tooltip; sempre nel DOM con ID univoco; visibile solo all’interazione
  • aria-labelledby sul trigger (punta all’ID del tooltip) — usare quando il tooltip è il nome accessibile del trigger (es. pulsante icona-only)
  • aria-describedby sul trigger (punta all’ID del tooltip) — usare quando il tooltip è informazione descrittiva aggiuntiva

Attributi ARIA

Attributo Valori Condizione
aria-labelledby ID del tooltip quando iconOnly è true — il tooltip fornisce il nome accessibile del trigger
aria-describedby ID del tooltip quando iconOnly è false — il tooltip è descrizione aggiuntiva (funzione title)
Tasto Azione
Tab Naviga verso il trigger
Enter Attiva/mostra il tooltip in modo persistente
Escape Chiude il tooltip attivo e mantiene il focus sul trigger

Gestione del focus

  • Focus visibile: lo stile :focus-visible è sempre visibile e non viene rimosso via CSS
  • Il tooltip si mostra automaticamente al focus sul trigger e si nasconde quando il focus lascia completamente il componente

Screen reader

  • Quando il tooltip usa aria-labelledby, il suo contenuto funge da nome accessibile del trigger (es. per un button icona-only)
  • Quando il tooltip usa aria-describedby, il suo contenuto viene letto come descrizione aggiuntiva dopo il nome del trigger
  • Il contenuto del tooltip è sempre presente nel DOM con un ID univoco, garantendo la disponibilità per le tecnologie assistive indipendentemente dalla visibilità visuale

Stili CSS

Classi Base

  • .has-tooltip: Wrapper del componente — Layout: relative
  • .rtds-tooltip-button: Trigger del tooltip — Layout: flex, w-max, h-min; Background: transparent
  • .rtds-tooltip: Contenitore del tooltip — Background: background-07 (scuro); Testo: content-inverse (chiaro); Ombra: shadow-md

Classi di Stato

  • .is-visible: Rende visibile il tooltip

Esempi di utilizzo

<!-- Tooltip come etichetta primaria (aria-labelledby) -->
<span class="has-tooltip">
  <button type="button" class="rtds-tooltip-button" aria-labelledby="tooltip-info">
    <svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#outline--information-circle"></use></svg>
  </button>
  <span id="tooltip-info" class="rtds-tooltip" role="tooltip">Informazioni aggiuntive</span>
</span>

<!-- Tooltip come descrizione aggiuntiva (aria-describedby) -->
<span class="has-tooltip">
  <button type="button" class="rtds-tooltip-button" aria-describedby="tooltip-desc">
    Azione principale
  </button>
  <span id="tooltip-desc" class="rtds-tooltip" role="tooltip">Questa azione non può essere annullata</span>
</span>

Note

  • Il componente richiede JavaScript per il funzionamento completo
  • Non sono ancora disponibili varianti di colore “light” (sfondo chiaro, testo scuro)
  • Il posizionamento del tooltip non è ancora completamente implementato
  • La larghezza massima è fissa (25ch per default, 20ch per small)