I'm trying to implement the tippy.js
tooltip and change the theme based on the local storage value darkMode
as an AlpineJs
custom directive.
The code below works more or less fine with the latest bit that if I toggle the dark-mode switch, which changes the local localStorage item value of darkMode
, I need a page refresh to get the new value.
How can I get the value (JSON.parse(localStorage.getItem('darkMode'))
) while I change it?
document.addEventListener('alpine:init', () => {
Alpine.directive('tooltip', (el, {expression, modifiers}) => {
tippy(el, {
content: expression,
placement: modifiers[0] ?? 'auto',
theme: JSON.parse(localStorage.getItem('darkMode')) ?'blue':'light-border'
})
})
})
<button type="button" x-tooltip.left="I'm a tooltip">Hover me</button>
<body class="font-sans antialiased h-full"
x-data="{'darkMode': false}"
x-init="
darkMode = JSON.parse(localStorage.getItem('darkMode'));
$watch('darkMode', value => localStorage.setItem('darkMode', JSON.stringify(value)))"
x-cloak
>
<!-- some html -->
</body>
<input id="toggle" type="checkbox" :value="darkMode" @change="darkMode = !darkMode"/>
As you see a Tippy.js instance and the localStorage
is not reactive. After creating a Tippy.js instance we need to use the _tippy
property on each element if we want to change a property. To make it a little bit easier, I modified the tooltip directive to add a custom class tooltips
, that we use to loop over each Tippy.js instance.
document.addEventListener('alpine:init', () => {
Alpine.directive('tooltip', (el, { expression, modifiers }) => {
tippy(el, {
content: expression,
placement: modifiers[0] ?? 'auto',
theme: JSON.parse(localStorage.getItem('darkMode')) ? 'blue' : 'light-border'
})
el.classList.add('tooltips')
})
})
And in the $watch
magic, we use the tooltips
class to find all of the Tippy.js instances and set the new theme on them.
<body class="font-sans antialiased h-full"
x-data="{'darkMode': false}"
x-init="
darkMode = JSON.parse(localStorage.getItem('darkMode'));
$watch('darkMode', value => {
localStorage.setItem('darkMode', JSON.stringify(value))
Array.from(document.querySelectorAll('.tooltips')).forEach(
el => el._tippy.setProps({ theme: value ? 'blue' : 'light-border' }))
})"
x-cloak
>
<!-- some html -->
</body>