I want to ask. I have a layout, there is a button when i click the button, a pop up will appear, the problem is when the modal appears, there are some components that are not dimmed, such as the button and the navbar as shown in the picture, I use vue cli and tailwind and for the modal I use flowbite. I've been looking for a way but still can't find it. Can anyone help me?
My website currently has a mobile-based display
this the web without modal
and this is the web when the button is clicked
here is the code in navbarWhite.vue
<template>
<header class="sticky h-14 top-0 z-50 bg-white" :class="boxShadow">
<div class="flex flex-row">
<div class="absolute" v-if="srcPictureLeft">
<img
#click="onClickBack"
class="ml-7 py-4 cursor-pointer text-black"
:src="require(`../assets/icon/${srcPictureLeft}`)"
/>
</div>
<div v-else></div>
<div class="py-4 relative mx-auto font-semibold text-black text-xl">
{{ title }}
</div>
</div>
</header>
</template>
<style>
</style>
<script>
export default {
name: "NavbarWhite",
props: {
onClickBack: {
type: Function,
},
title: String,
srcPictureLeft: String,
boxShadow: String,
},
};
</script>
and this is the button component (ButtonBottom.vue)
<template>
<div
class="
sticky
w-full
absolute
mb-0
bottom-0
z-50
bg-white
h-16
drop-shadow-[0_0_4px_rgba(0,0,0,0.25)]
"
>
<div class="mx-[30px] py-2">
<button-primary
class="
bg-green-button
text-white
hover:bg-green-button-darker hover:rounded-[32px]
"
>
<slot>Button</slot>
</button-primary>
</div>
</div>
</template>
<script>
import ButtonPrimary from "#/components/ButtonPrimary.vue";
export default {
name: "ButtonBottom",
components: {
ButtonPrimary,
},
};
</script>
and this is the parent where all the component called
<template>
<div class="h-screen relative">
<div class="h-[94%]">
<navbar-white
boxShadow="shadow-[0_0_10px_0_rgba(0,0,0,0.25)]"
srcPictureLeft="backIconBlack.svg"
:onClickBack="goBack"
title="Ringkasan Transaksi"
/>
<div class="mt-10 mx-[30px]">
<div class="flex flex-row justify-between mb-7">
<div class="font-semibold">No. Rekening</div>
<div>12345678</div>
</div>
<div class="flex flex-row justify-between mb-7">
<div class="font-semibold">Nama Penerima</div>
<div>Lorem Ipsum</div>
</div>
<div class="flex flex-row justify-between mb-4">
<div class="font-semibold">Bank Tujuan</div>
<div>12345678</div>
</div>
<hr class="mb-4" />
<div class="flex flex-row justify-between mb-7">
<div class="font-semibold">Nominal</div>
<div>Rp 200.000</div>
</div>
<div class="flex flex-row justify-between mb-4">
<div class="font-semibold">Fee</div>
<div>Rp 2.500</div>
</div>
<div class="flex flex-row justify-between">
<div class="font-semibold">Total</div>
<div class="font-semibold">Rp 202.500</div>
</div>
</div>
</div>
<button-bottom data-modal-toggle="biayaAdmin">Selanjutnya</button-bottom>
<!-- modal start here -->
<div
id="biayaAdmin"
tabindex="-1"
class="
hidden
overflow-y-auto overflow-x-hidden
fixed
top-0
right-0
left-0
z-50
w-full
md:inset-0
h-modal
md:h-full
"
>
<div class="relative p-4 w-full max-w-md h-full md:h-auto">
<!-- Modal content -->
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
<!-- Modal header -->
<div
class="
flex
justify-between
items-center
p-5
rounded-t
border-b
dark:border-gray-600
"
>
<h3 class="text-xl font-medium text-gray-900 dark:text-white">
Small modal
</h3>
<button
type="button"
class="
text-gray-400
bg-transparent
hover:bg-gray-200 hover:text-gray-900
rounded-lg
text-sm
p-1.5
ml-auto
inline-flex
items-center
dark:hover:bg-gray-600 dark:hover:text-white
"
data-modal-toggle="biayaAdmin"
>
<svg
aria-hidden="true"
class="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd"
></path>
</svg>
<span class="sr-only">Close modal</span>
</button>
</div>
<!-- Modal body -->
<div class="p-6 space-y-6">
<p
class="text-base leading-relaxed text-gray-500 dark:text-gray-400"
>
With less than a month to go before the European Union enacts new
consumer privacy laws for its citizens, companies around the world
are updating their terms of service agreements to comply.
</p>
<p
class="text-base leading-relaxed text-gray-500 dark:text-gray-400"
>
The European Union’s General Data Protection Regulation (G.D.P.R.)
goes into effect on May 25 and is meant to ensure a common set of
data rights in the European Union. It requires organizations to
notify users as soon as possible of high-risk data breaches that
could personally affect them.
</p>
</div>
<!-- Modal footer -->
<div
class="
flex
items-center
p-6
space-x-2
rounded-b
border-t border-gray-200
dark:border-gray-600
"
>
<button
data-modal-toggle="biayaAdmin"
type="button"
class="
text-white
bg-blue-700
hover:bg-blue-800
focus:ring-4 focus:outline-none focus:ring-blue-300
font-medium
rounded-lg
text-sm
px-5
py-2.5
text-center
dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-800
"
>
I accept
</button>
<button
data-modal-toggle="biayaAdmin"
type="button"
class="
text-gray-500
bg-white
hover:bg-gray-100
focus:ring-4 focus:outline-none focus:ring-gray-200
rounded-lg
border border-gray-200
text-sm
font-medium
px-5
py-2.5
hover:text-gray-900
focus:z-10
dark:bg-gray-700
dark:text-gray-300
dark:border-gray-500
dark:hover:text-white
dark:hover:bg-gray-600
dark:focus:ring-gray-600
"
>
Decline
</button>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import ButtonBottom from "#/components/ButtonBottom.vue";
import NavbarWhite from "#/components/NavbarWhite.vue";
export default {
name: "TransactionSummary",
components: {
ButtonBottom,
NavbarWhite,
},
methods: {
goBack() {
this.$router.go(-1);
},
},
};
</script>
The css z-index of your header and footer might be higher than the z-index of the overlay mask.
Try inspecting the elements and evaluate their z-index values, try forcing new values to ensure that the z-index of the header and footer is a lower value than the grey overlay mask.
The issue might be the lack of a z-index value on some of those elements to indicate which should appear over the top of another.
https://www.w3schools.com/cssref/pr_pos_z-index.asp
I have the following inertia link component
<inertia-link v-for="project in $page.props.user.favorite_projects" :key="project.id" class="flex items-center px-6 py-2 mb-1 text-sm leading-6 text-gray-300 transition duration-150 ease-in-out group focus:outline-none focus:bg-gray-700 hover:text-white hover:bg-gray-700" :href="route('projects.show',project.slug)">
<div class="w-3 h-3 mr-3 overflow-hidden rounded-full">
<div class="w-full h-full" style="background-color = {{ project.color }};">
</div>
</div>
{{ project.project_name }}
</inertia-link>
Where project.color contains a hex color value like #fc8181, which is used to color the element based on the project.
However, the circle with this color value is not being shown in the dom.
Is there a way to display the project color as background color?
you need to bind the style, try style
:style="{ background-color: project.color }"
I'm having some issues with how to pull data from Alpine to work in LiveWire.
Code Example
<div x-data #click="$dispatch('popup', { name: 'Hello World', drip: 'yes' })" class="border-2 border-white flex font-semibold hover:bg-yellow-400 hover:border-yellow-200 items-center justify-center p-1.5 rounded-md shadow-sm text-base text-black transition-all md:w-8/12 lg:w-6/12 bg-green-300 cursor-pointer">Click Me</div>
<div x-data="{ popupinfo: false, drip: null }" x-on:popup.window="{ popupinfo = true }" #popup.window="{ name = $event.detail.name, drip = $event.detail.drip }" x-show="popupinfo" x-cloak>
<h3 class="text-lg leading-6 font-bold text-gray-900" id="modal-title" x-text="name"></h3>
<div class="flex items-center justify-start">
<template x-if="drip == 'yes'">
<div>True</div>
</template>
<template x-if="drip == 'no'">
<div>False</div>
</template>
</div>
<div class="bg-yellow-400 flex items-center justify-between px-3 py-2 rounded-xl my-2 cursor-pointer transition-colors tracking-tight"
wire:click="$emit('addToBasket', {{ $drip }})"
#click="$dispatch('addtobasket')">
<div class="text-sm">
<span class="font-bold">2 Uploads</span> a day
</div>
<div class="bg-white font-semibold px-2 py-1 rounded-md text-sm tracking-tighter"> Monthly</div>
</div>
</div>
Look on line 15 (wire:click="$emit('addToBasket', {{ $drip }})"). How can I add the drip data to the emit. Right now I've wrapped it in a {{ }} (Which is on purpose). I don't know how to call it for the emit.
You can see how it runs here
https://codepen.io/bitvalentine/pen/wvJEYYX
You can use the livewire #entangle() feature to share property state between alpine and livewire.
just define your alpine drip property like below and set its value on your livewire property
<div x-data="{ popupinfo: false, #entangle('drip') }" x-on:popup.window="{ popupinfo = true }" #popup.window="{ name = $event.detail.name, drip = $event.detail.drip }" x-show="popupinfo" x-cloak>
on your livewire component
public $drip = null;
I am using TailwindCSS. I have an SVG that when clicked, displays an absolute component.
<div tabIndex={0} className="relative group">
<svg xmlns="http://www.w3.org/2000/svg" className="w-5 h-5 text-indigo-600 outline-none cursor-pointer" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
</svg>
<div className="absolute top-0 z-50 hidden h-auto max-w-sm overflow-y-auto text-left transform translate-x-full bg-white rounded shadow-2xl max-h-60 group-focus:flex min-w-screen -right-full">
<div className="flex flex-col">
<p className="px-4 py-2 font-bold text-indigo-600 bg-indigo-100 text center">Additional Announcements</p>
<div className="flex flex-col px-4 divide-y divide-gray-200">
<div className="flex flex-col py-2 text-gray-700">
<span className="font-medium text-gray-700">{existingAnnLocalisedDate}</span>
<div className="flex">
<a className="leading-snug cursor-pointer hover:underline" href={ann.url} onClick={() => Logger({ key: "ANNOUNCEMENT_CLICKED" })} rel="noopener noreferrer" target="_blank">
{ann.headline}
</a>
{ ann.isPriceSensitive && (
<span className="inline-flex items-center justify-center w-auto h-auto ml-1 font-medium text-center cursor-default" title="Price sensitive">
💰
</span>
)}
</div>
</div>
</div>
</div>
</div>
</div>
This works as expected, however when I click an <a href="" /> element, it doesn't actually open that link - it just drops the focus on that component. How can I make it so that not only does it drop the focus, but it also opens the link in a new tab, as the code suggests?
Thank you!
I use navbar component from tailwind ui. It's looks like something like this:
<!-- Profile dropdown -->
<div class="ml-3 relative">
<div>
<button
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-white transition duration-150 ease-in-out"
id="user-menu"
aria-label="User menu"
aria-haspopup="true"
>
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt
/>
</button>
</div>
<!--
Profile dropdown panel, show/hide based on dropdown state.
Entering: "transition ease-out duration-100"
From: "transform opacity-0 scale-95"
To: "transform opacity-100 scale-100"
Leaving: "transition ease-in duration-75"
From: "transform opacity-100 scale-100"
To: "transform opacity-0 scale-95"
-->
<div class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg">
<div
class="py-1 rounded-md bg-white shadow-xs"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu"
>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Your Profile</a>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Settings</a>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Sign out</a>
</div>
</div>
</div>
In this case when I run this code in vue.js navbar dropdown menu status is open by default. How can set status closed by defaul?
Here is preview:
I'm not sure if anyone is following this question right now but I'm sharing my solution.
In the snippet to the dropdown code there was a comment saying:
<!--
Profile dropdown panel, show/hide based on dropdown state.
Entering: "transition ease-out duration-100"
From: "transform opacity-0 scale-95"
To: "transform opacity-100 scale-100"
Leaving: "transition ease-in duration-75"
From: "transform opacity-100 scale-100"
To: "transform opacity-0 scale-95"
-->
It's basically telling the state of dropdown is changing based on classes names so you'd have to make them dynamic like this:
<div :class="`origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg transition ease-${dropdown ? 'out' : 'in'} duration-${dropdown ? '100' : '75'} transform opacity-${dropdown ? '100' : '0'} scale-${dropdown ? '100' : '95'}`">
now the classes will depend on the dropdown value which is just a property of your component that can be changed via a click event like this:
export default {
name: 'TheNavBar',
data() {
return {
dropdown: false,
}
},
}
<div>
<button
id="user-menu"
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-white transition duration-150 ease-in-out"
aria-label="User menu"
aria-haspopup="true"
#click="dropdown = !dropdown"
>
</button>
</div>
I was using alpinejs and included it using CDN.
It worked for me when I put the following in the div that was wrapping the whole component:
x-data="{ open: false }"
The below went into the (User profile image) button div
#click="open = true"
And finally, this went into the drop-down div
x-show="open" #click.away="open = false"
I'm exactly using the same component and came here to find an answer :(
Since nobody answered it, here is where I've been:
It's explicitly said that you'll need to use Javascript with some Tailwind UI component like this one.
But I've done with no JS, only a CSS tricks and a slightly different markup and a simpler animation (but still smooth! You can see the fiddle on the bottom of this answer).
The markup: I've just removed the div wraper arround the avatar button to benefits from the ~ CSS selector, and I've added an id #user-menu-dropdown:
<!-- Profile dropdown -->
<div class="ml-3 relative">
<button
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-white transition duration-150 ease-in-out"
id="user-menu" aria-label="User menu" aria-haspopup="true">
<img class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt=""/>
</button>
<div id="user-menu-dropdown" class="menu-hidden origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg">
<div
class="py-1 rounded-md bg-white shadow-xs"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu"
>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Your Profile</a>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Settings</a>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Sign out</a>
</div>
</div>
</div>
And here is my LESS
#user-menu ~ #user-menu-dropdown
#apply transform
#apply ease-in duration-75 opacity-0 scale-0
#user-menu ~ #user-menu-dropdown:focus-within, #user-menu:focus ~ #user-menu-dropdown
#apply ease-out duration-100 opacity-100 scale-100
And here is the results, using the generated CSS
Hope it will help you
If the Alpine JS is working fine. Just Copy-paste this code and you will be good to go.
<!-- Profile dropdown -->
<div class="ml-3 relative" x-data="{ dropdown: false }">
<div>
<button x-on:click="dropdown = ! dropdown" type="button" class="max-w-xs bg-gray-800 rounded-full flex items-center text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-800 focus:ring-white" id="user-menu-button" aria-expanded="false" aria-haspopup="false">
<span class="sr-only">Open user menu</span>
<img class="h-8 w-8 rounded-full" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
</button>
</div>
<div x-show="dropdown" class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none" role="menu" aria-orientation="vertical" aria-labelledby="user-menu-button" tabindex="-1">
<!-- Active: "bg-gray-100", Not Active: "" -->
Your Profile
Settings
Sign out
</div>
</div>
Explanation of what I do
I just simply added x-data="{ dropdown: false }" in the parent div to hide the menu at the initial state.
Then, I added x-on:click="dropdown = ! dropdown" on the button to toggle the menu.
And lastly, I added x-show="dropdown" in the menu div. to show or hide the dropdown based on its value.
You can use any text at the spot of dropdown. Because its works like a variable.
As pointed out in previous answers one can use Vue.js or some smart CSS to solve the problem. If you don't want to make your page heavy by using Vue or use CSS which has limitations then you can use alpinejs. This is what Tailwindui is using in their demo.
You can use alpinejs either by installing it via yarn or npm or simply install it from CDN.
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine#v2.7.0/dist/alpine.min.js" defer></script>
You don't need to write even one line of javascript. If you installed via npm or yarn then import it to your project.
import "alpinejs";
Open the HTML with navigation code.
Add x-data directive.
<!-- Profile dropdown -->
<div class="ml-3 relative" x-data="open = false">
Now add x-click directive to the element that is clicked to reveal the dropdown.
<button
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-white transition duration-150 ease-in-out"
id="user-menu"
aria-label="User menu"
aria-haspopup="true"
x-on:click="open=true"
>
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt
/>
</button>
Finally modify the div that nests the dropdown elements.
<div class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg" x-show="open" x-on:click.away="open = false">
x-on:click.away directive will close the dropdown when mouse is clicked anywhere else.
To polish it off you can use Alpine transition directives to the previous div.
<div class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg" x-show="open" x-on:click.away="open = false" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="opacity-0 -translate-y-1" x-transition:enter-end="opacity-100 translate-y-0" x-transition:leave="transition ease-in duration-150" x-transition:leave-start="opacity-100 translate-y-0" x-transition:leave-end="opacity-0 -translate-y-1">
If you have more than two dropdowns then use data directive as under
<div x-data="{openDropdown1: false, openDropdown2: false}"
Tailwind UI only provides example static html. You'll need to use your JS framework (Vue.js) to dynamically generate similar html that varies based on the state of your app. In general you need to:
1- add a boolean state variable that controls whether the menu is currently displayed or not. Initialize it to false so the menu is hidden by default.
data() {
return {
show: false,
}
}
2- Add a click handler to the menu button to toggle this variable.
<button #click="show = !show">Menu</button>
3- Only render the menu when show is true. You can do this with v-if
<div v-if="show" class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg">
//...menu content
</div>
4- Animate the menu when it gets displayed or hidden. You can do this by wrapping the menu in a Vue.js <transition> component.
<transition
enter-active-class="transition ease-out duration-100"
enter-from-class="transform opacity-0 scale-95"
enter-to-class="transform opacity-100 scale-100"
leave-active-class="transition ease-in duration-75"
leave-from-class="transform opacity-100 scale-100"
leave-to-class="transform opacity-0 scale-95"
>
<div v-if="show" class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg">
//...menu content
</div>
</transition>
Here is a full working example in Vue 3:
https://codepen.io/mpvosseller/pen/RwoNaVz
Notes:
In Vue 2 you should use enter-class and leave-class instead of enter-from-class and leave-from-class
In React you can use Tailwind's Headless UI React Transition component for similar functionality.
use v-on:click and v-show
<!-- ProfileNavDropdown.vue -->
<template>
<div class="ml-3 relative">
<div v-on:click="isActive = !isActive">
<button
class="flex text-sm border-2 border-transparent rounded-full focus:outline-none focus:border-white transition duration-150 ease-in-out"
id="user-menu"
aria-label="User menu"
aria-haspopup="true"
>
<img
class="h-8 w-8 rounded-full"
src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80"
alt
/>
</button>
</div>
<!--
Profile dropdown panel, show/hide based on dropdown state.
Entering: "transition ease-out duration-100"
From: "transform opacity-0 scale-95"
To: "transform opacity-100 scale-100"
Leaving: "transition ease-in duration-75"
From: "transform opacity-100 scale-100"
To: "transform opacity-0 scale-95"
-->
<div v-show="isActive" class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg">
<div
class="py-1 rounded-md bg-white shadow-xs"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu"
>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Your Profile</a>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Settings</a>
<a
href="#"
class="block px-4 py-2 text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out"
role="menuitem"
>Sign out</a>
</div>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
isActive: false,
}
},
}
</script>
I had this same issue, here is a solution I discovered from my little research:
<!-- vue template -->
<template>
<div class="relative">
<button #click="isOpen = !isOpen" class="relative z-10 block h-8 w-8 rounded-full overflow-hidden border-2 border-gray-600 focus:outline-none focus:border-white">
<img class="h-full w-full object-cover" src="https://images.unsplash.com/photo-1487412720507-e7ab37603c6f?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=256&q=80" alt="Your avatar">
</button>
<button v-if="isOpen" #click="isOpen = false" tabindex="-1" class="fixed inset-0 h-full w-full bg-black opacity-50 cursor-default"></button>
<div v-if="isOpen" class="absolute right-0 mt-2 py-2 w-48 bg-white rounded-lg shadow-xl">
Account settings
Support
Sign out
</div>
</div>
</template>
<script>
//javascript
export default {
data() {
return {
isOpen: false
}
},
created() {
const handleEscape = (e) => {
if (e.key === 'Esc' || e.key === 'Escape') {
this.isOpen = false
}
}
document.addEventListener('keydown', handleEscape)
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('keydown', handleEscape)
})
}
}
</script>
I hope this helps, you can see more here
Adding to #Andreas Hunter's solution, you may use the more convenient headless-ui (Tailwind CSS) for Vue (click here). It is also available for React. Headless UI is designed to integrate beautifully with Tailwind CSS.
Use Menu component for dropdowns:
<template>
<Menu>
<MenuButton> More </MenuButton>
<MenuItems>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Account settings </a>
</MenuItem>
<MenuItem v-slot="{ active }">
<a :class="{ 'bg-blue-500': active }" href="/account-settings"> Documentation </a>
</MenuItem>
<MenuItem v-slot="{ active }" disabled>
<span :class="{ 'bg-blue-500': active }"> Invite a friend (coming soon!) </span>
</MenuItem>
</MenuItems>
</Menu>
</template>
<script>
import { Menu, MenuButton, MenuItems, MenuItem } from '#headlessui/vue'
export default {
components: {
Menu,
MenuButton,
MenuItems,
MenuItem,
},
}
</script>
You don't have to worry about its state anymore.
Since tailwind by default handles the dropdown (open and close, even when you click outside the dropdown). It just programmatically hides the dropdown.
I used a javascript one-line solution by simulating a click on the document body. That way, the dropdown automatically close while you still maintain its animations. And you could simulate a click event on the button/element to open the dropdown.
document.querySelector('body').click()
For anyone struggling with this, the solution is much simpler than all the replies above.
Add this class to the div (so it is invisible when the page first loads): "invisible".
Add another class called "profile-menu".
<div class="invisible profile-menu" role="menu" aria-orientation="vertical" aria-labelledby="user-menu-button" tabindex="-1">
In Javascript at the bottom of your page add this:
const navbarBtn = document.querySelector(".close-profile-bar");
const profileMenu = document.querySelector(".profile-menu");
navbarBtn.addEventListener("click", () => {
let results = profileMenu.classList.contains('invisible');
if(results){
profileMenu.classList.remove('invisible');
profileMenu.classList.add('visible');
} else {
profileMenu.classList.remove('visible');
profileMenu.classList.add('invisible');
}
});
The above will just remove or add the invisible or invisible class to the profile div.