<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"
}
.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);
}
@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;
}
}
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
Componente tooltip accessibile che simula l’attributo title con miglioramenti significativi per l’accessibilità e l’usabilità.
Il tooltip può essere usato come:
aria-labelledby="{idTooltip}"title) — usa aria-describedby="{idTooltip}"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’interazioneIl 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.
default: Tooltip con button con icona come trigger — il tooltip ha funzione di etichetta testuale primaria (nome accessibile), usa aria-labelledbytitle: Tooltip con funzione di title — etichetta testuale secondaria (informazione descrittiva aggiuntiva), usa aria-describedbylink: Tooltip con link come triggerContesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context
.config.ymlusati 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.
label (stringa, obbligatorio): Testo del trigger (button/link)content (stringa, obbligatorio): Contenuto del tooltipid (stringa, obbligatorio): ID univoco per l’attributo aria-describedby o aria-labelledbywrapperTag (stringa, opzionale): Tag del wrapper (default: “span”)classes (stringa, opzionale): Classi CSS aggiuntive per il wrapperbuttonClasses (stringa, opzionale): Classi CSS aggiuntive per il triggerhref (stringa, opzionale): URL per il trigger linkbuttonType (stringa, opzionale): Tipo del button se non è un link (default: “button”)Livello AA — criteri pertinenti:
aria-labelledby o aria-describedby in base al caso d’usoEscape)aria-labelledby (quando il tooltip è il nome accessibile) o aria-describedby (quando è una descrizione aggiuntiva)<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’interazionearia-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| 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 |
:focus-visible è sempre visibile e non viene rimosso via CSSaria-labelledby, il suo contenuto funge da nome accessibile del trigger (es. per un button icona-only)aria-describedby, il suo contenuto viene letto come descrizione aggiuntiva dopo il nome del trigger.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.is-visible: Rende visibile il tooltip<!-- 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>