[{"data":1,"prerenderedAt":1550},["ShallowReactive",2],{"article:creating-popover-component-with-vue3":3,"\u002Fblog\u002Fcreating-popover-component-with-vue3-surround":1539},{"id":4,"title":5,"author":6,"body":7,"date":1528,"description":1529,"extension":1530,"image":1531,"meta":1532,"minRead":100,"navigation":328,"path":1533,"published":328,"seo":1534,"stem":1535,"tags":1536,"__hash__":1538},"blog\u002Fblog\u002Fcreating-popover-component-with-vue3.md","Creating custom popover component with Vue 3 and Tailwind CSS","Baljeet Singh",{"type":8,"value":9,"toc":1526},"minimark",[10,14,17,43,364,375,382,400,407,797,803,977,980,987,990,993,1383,1386,1392,1406,1510,1513,1519,1522],[11,12,13],"p",{},"In this article, we'll see how we can create a custom design sytem popover component with vue 3 and tailwind css.",[11,15,16],{},"We can start by creating a new vue project.",[18,19,24],"pre",{"className":20,"code":21,"language":22,"meta":23,"style":23},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","npm create vue@latest\n","bash","",[25,26,27],"code",{"__ignoreMap":23},[28,29,32,36,40],"span",{"class":30,"line":31},"line",1,[28,33,35],{"class":34},"sBMFI","npm",[28,37,39],{"class":38},"sfazB"," create",[28,41,42],{"class":38}," vue@latest\n",[18,44,46],{"className":20,"code":45,"language":22,"meta":23,"style":23},"✔ Project name: … \u003Cyour-project-name>\n✔ Add TypeScript? … No \u002F Yes\n✔ Add JSX Support? … No \u002F Yes\n✔ Add Vue Router for Single Page Application development? … No \u002F Yes\n✔ Add Pinia for state management? … No \u002F Yes\n✔ Add Vitest for Unit testing? … No \u002F Yes\n✔ Add an End-to-End Testing Solution? … No \u002F Cypress \u002F Nightwatch \u002F Playwright\n✔ Add ESLint for code quality? … No \u002F Yes\n✔ Add Prettier for code formatting? … No \u002F Yes\n✔ Add Vue DevTools 7 extension for debugging? (experimental) … No \u002F Yes\n\nScaffolding project in .\u002F\u003Cyour-project-name>...\nDone.\n",[25,47,48,76,98,119,155,181,207,245,271,296,323,330,358],{"__ignoreMap":23},[28,49,50,53,56,59,62,66,69,73],{"class":30,"line":31},[28,51,52],{"class":34},"✔",[28,54,55],{"class":38}," Project",[28,57,58],{"class":38}," name:",[28,60,61],{"class":38}," …",[28,63,65],{"class":64},"sMK4o"," \u003C",[28,67,68],{"class":38},"your-project-nam",[28,70,72],{"class":71},"sTEyZ","e",[28,74,75],{"class":64},">\n",[28,77,79,81,84,87,89,92,95],{"class":30,"line":78},2,[28,80,52],{"class":34},[28,82,83],{"class":38}," Add",[28,85,86],{"class":38}," TypeScript?",[28,88,61],{"class":38},[28,90,91],{"class":38}," No",[28,93,94],{"class":38}," \u002F",[28,96,97],{"class":38}," Yes\n",[28,99,101,103,105,108,111,113,115,117],{"class":30,"line":100},3,[28,102,52],{"class":34},[28,104,83],{"class":38},[28,106,107],{"class":38}," JSX",[28,109,110],{"class":38}," Support?",[28,112,61],{"class":38},[28,114,91],{"class":38},[28,116,94],{"class":38},[28,118,97],{"class":38},[28,120,122,124,126,129,132,135,138,141,144,147,149,151,153],{"class":30,"line":121},4,[28,123,52],{"class":34},[28,125,83],{"class":38},[28,127,128],{"class":38}," Vue",[28,130,131],{"class":38}," Router",[28,133,134],{"class":38}," for",[28,136,137],{"class":38}," Single",[28,139,140],{"class":38}," Page",[28,142,143],{"class":38}," Application",[28,145,146],{"class":38}," development?",[28,148,61],{"class":38},[28,150,91],{"class":38},[28,152,94],{"class":38},[28,154,97],{"class":38},[28,156,158,160,162,165,167,170,173,175,177,179],{"class":30,"line":157},5,[28,159,52],{"class":34},[28,161,83],{"class":38},[28,163,164],{"class":38}," Pinia",[28,166,134],{"class":38},[28,168,169],{"class":38}," state",[28,171,172],{"class":38}," management?",[28,174,61],{"class":38},[28,176,91],{"class":38},[28,178,94],{"class":38},[28,180,97],{"class":38},[28,182,184,186,188,191,193,196,199,201,203,205],{"class":30,"line":183},6,[28,185,52],{"class":34},[28,187,83],{"class":38},[28,189,190],{"class":38}," Vitest",[28,192,134],{"class":38},[28,194,195],{"class":38}," Unit",[28,197,198],{"class":38}," testing?",[28,200,61],{"class":38},[28,202,91],{"class":38},[28,204,94],{"class":38},[28,206,97],{"class":38},[28,208,210,212,214,217,220,223,226,228,230,232,235,237,240,242],{"class":30,"line":209},7,[28,211,52],{"class":34},[28,213,83],{"class":38},[28,215,216],{"class":38}," an",[28,218,219],{"class":38}," End-to-End",[28,221,222],{"class":38}," Testing",[28,224,225],{"class":38}," Solution?",[28,227,61],{"class":38},[28,229,91],{"class":38},[28,231,94],{"class":38},[28,233,234],{"class":38}," Cypress",[28,236,94],{"class":38},[28,238,239],{"class":38}," Nightwatch",[28,241,94],{"class":38},[28,243,244],{"class":38}," Playwright\n",[28,246,248,250,252,255,257,260,263,265,267,269],{"class":30,"line":247},8,[28,249,52],{"class":34},[28,251,83],{"class":38},[28,253,254],{"class":38}," ESLint",[28,256,134],{"class":38},[28,258,259],{"class":38}," code",[28,261,262],{"class":38}," quality?",[28,264,61],{"class":38},[28,266,91],{"class":38},[28,268,94],{"class":38},[28,270,97],{"class":38},[28,272,274,276,278,281,283,285,288,290,292,294],{"class":30,"line":273},9,[28,275,52],{"class":34},[28,277,83],{"class":38},[28,279,280],{"class":38}," Prettier",[28,282,134],{"class":38},[28,284,259],{"class":38},[28,286,287],{"class":38}," formatting?",[28,289,61],{"class":38},[28,291,91],{"class":38},[28,293,94],{"class":38},[28,295,97],{"class":38},[28,297,299,301,303,305,308,312,315,317,320],{"class":30,"line":298},10,[28,300,52],{"class":34},[28,302,83],{"class":38},[28,304,128],{"class":38},[28,306,307],{"class":38}," DevTools",[28,309,311],{"class":310},"sbssI"," 7",[28,313,314],{"class":38}," extension",[28,316,134],{"class":38},[28,318,319],{"class":38}," debugging?",[28,321,322],{"class":71}," (experimental) … No \u002F Yes\n",[28,324,326],{"class":30,"line":325},11,[28,327,329],{"emptyLinePlaceholder":328},true,"\n",[28,331,333,336,339,342,345,348,350,352,355],{"class":30,"line":332},12,[28,334,335],{"class":34},"Scaffolding",[28,337,338],{"class":38}," project",[28,340,341],{"class":38}," in",[28,343,344],{"class":38}," .\u002F",[28,346,347],{"class":64},"\u003C",[28,349,68],{"class":38},[28,351,72],{"class":71},[28,353,354],{"class":64},">",[28,356,357],{"class":38},"...\n",[28,359,361],{"class":30,"line":360},13,[28,362,363],{"class":34},"Done.\n",[11,365,366,367,374],{},"After that, we can install Tailwind CSS in the project. We can do this by following this ",[368,369,373],"a",{"href":370,"rel":371},"https:\u002F\u002Ftailwindcss.com\u002Fdocs\u002Fguides\u002Fvite#vue",[372],"nofollow","Link",".",[11,376,377,378,381],{},"Lastly, we need to install ",[25,379,380],{},"vueuse"," library by following this command. We'll shortly see why it is required.",[18,383,385],{"className":20,"code":384,"language":22,"meta":23,"style":23},"npm install @vueuse\u002Fcore @vueuse\u002Fcomponents\n",[25,386,387],{"__ignoreMap":23},[28,388,389,391,394,397],{"class":30,"line":31},[28,390,35],{"class":34},[28,392,393],{"class":38}," install",[28,395,396],{"class":38}," @vueuse\u002Fcore",[28,398,399],{"class":38}," @vueuse\u002Fcomponents\n",[11,401,402,403,406],{},"Now, we can start by creating a ",[25,404,405],{},"popover"," component.",[18,408,413],{"className":409,"code":410,"filename":411,"language":412,"meta":23,"style":23},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Cscript setup>\nimport { ref } from 'vue';\n\nconst isOpen = ref(false);\n\nconst togglePopover = () => {\n  isOpen.value = !isOpen.value;\n};\n\nconst closePopover = () => {\n  isOpen.value = false;\n};\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"relative inline-block\" @click=\"togglePopover\">\n    \u003Cdiv class=\"cursor-pointer\">\n      \u003Cslot name=\"trigger\">\u003C\u002Fslot>\n    \u003C\u002Fdiv>\n    \u003Cdiv\n      v-if=\"isOpen\"\n      class=\"absolute z-10 min-w-[150px] p-2 bg-white border border-gray-200 rounded-lg shadow-lg\"\n      @click.self=\"closePopover\"\n    >\n      \u003Cslot>\u003C\u002Fslot>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","component\u002Fpopover.vue","vue",[25,414,415,429,458,462,488,492,510,535,540,544,559,574,578,587,592,602,638,659,687,697,705,720,735,750,756,769,778,788],{"__ignoreMap":23},[28,416,417,419,423,427],{"class":30,"line":31},[28,418,347],{"class":64},[28,420,422],{"class":421},"swJcz","script",[28,424,426],{"class":425},"spNyl"," setup",[28,428,75],{"class":64},[28,430,431,435,438,441,444,447,450,452,455],{"class":30,"line":78},[28,432,434],{"class":433},"s7zQu","import",[28,436,437],{"class":64}," {",[28,439,440],{"class":71}," ref",[28,442,443],{"class":64}," }",[28,445,446],{"class":433}," from",[28,448,449],{"class":64}," '",[28,451,412],{"class":38},[28,453,454],{"class":64},"'",[28,456,457],{"class":64},";\n",[28,459,460],{"class":30,"line":100},[28,461,329],{"emptyLinePlaceholder":328},[28,463,464,467,470,473,476,479,483,486],{"class":30,"line":121},[28,465,466],{"class":425},"const",[28,468,469],{"class":71}," isOpen ",[28,471,472],{"class":64},"=",[28,474,440],{"class":475},"s2Zo4",[28,477,478],{"class":71},"(",[28,480,482],{"class":481},"sfNiH","false",[28,484,485],{"class":71},")",[28,487,457],{"class":64},[28,489,490],{"class":30,"line":157},[28,491,329],{"emptyLinePlaceholder":328},[28,493,494,496,499,501,504,507],{"class":30,"line":183},[28,495,466],{"class":425},[28,497,498],{"class":71}," togglePopover ",[28,500,472],{"class":64},[28,502,503],{"class":64}," ()",[28,505,506],{"class":425}," =>",[28,508,509],{"class":64}," {\n",[28,511,512,515,517,520,523,526,529,531,533],{"class":30,"line":209},[28,513,514],{"class":71},"  isOpen",[28,516,374],{"class":64},[28,518,519],{"class":71},"value",[28,521,522],{"class":64}," =",[28,524,525],{"class":64}," !",[28,527,528],{"class":71},"isOpen",[28,530,374],{"class":64},[28,532,519],{"class":71},[28,534,457],{"class":64},[28,536,537],{"class":30,"line":247},[28,538,539],{"class":64},"};\n",[28,541,542],{"class":30,"line":273},[28,543,329],{"emptyLinePlaceholder":328},[28,545,546,548,551,553,555,557],{"class":30,"line":298},[28,547,466],{"class":425},[28,549,550],{"class":71}," closePopover ",[28,552,472],{"class":64},[28,554,503],{"class":64},[28,556,506],{"class":425},[28,558,509],{"class":64},[28,560,561,563,565,567,569,572],{"class":30,"line":325},[28,562,514],{"class":71},[28,564,374],{"class":64},[28,566,519],{"class":71},[28,568,522],{"class":64},[28,570,571],{"class":481}," false",[28,573,457],{"class":64},[28,575,576],{"class":30,"line":332},[28,577,539],{"class":64},[28,579,580,583,585],{"class":30,"line":360},[28,581,582],{"class":64},"\u003C\u002F",[28,584,422],{"class":421},[28,586,75],{"class":64},[28,588,590],{"class":30,"line":589},14,[28,591,329],{"emptyLinePlaceholder":328},[28,593,595,597,600],{"class":30,"line":594},15,[28,596,347],{"class":64},[28,598,599],{"class":421},"template",[28,601,75],{"class":64},[28,603,605,608,611,614,616,619,622,624,627,629,631,634,636],{"class":30,"line":604},16,[28,606,607],{"class":64},"  \u003C",[28,609,610],{"class":421},"div",[28,612,613],{"class":425}," class",[28,615,472],{"class":64},[28,617,618],{"class":64},"\"",[28,620,621],{"class":38},"relative inline-block",[28,623,618],{"class":64},[28,625,626],{"class":425}," @click",[28,628,472],{"class":64},[28,630,618],{"class":64},[28,632,633],{"class":38},"togglePopover",[28,635,618],{"class":64},[28,637,75],{"class":64},[28,639,641,644,646,648,650,652,655,657],{"class":30,"line":640},17,[28,642,643],{"class":64},"    \u003C",[28,645,610],{"class":421},[28,647,613],{"class":425},[28,649,472],{"class":64},[28,651,618],{"class":64},[28,653,654],{"class":38},"cursor-pointer",[28,656,618],{"class":64},[28,658,75],{"class":64},[28,660,662,665,668,671,673,675,678,680,683,685],{"class":30,"line":661},18,[28,663,664],{"class":64},"      \u003C",[28,666,667],{"class":421},"slot",[28,669,670],{"class":425}," name",[28,672,472],{"class":64},[28,674,618],{"class":64},[28,676,677],{"class":38},"trigger",[28,679,618],{"class":64},[28,681,682],{"class":64},">\u003C\u002F",[28,684,667],{"class":421},[28,686,75],{"class":64},[28,688,690,693,695],{"class":30,"line":689},19,[28,691,692],{"class":64},"    \u003C\u002F",[28,694,610],{"class":421},[28,696,75],{"class":64},[28,698,700,702],{"class":30,"line":699},20,[28,701,643],{"class":64},[28,703,704],{"class":421},"div\n",[28,706,708,711,713,715,717],{"class":30,"line":707},21,[28,709,710],{"class":425},"      v-if",[28,712,472],{"class":64},[28,714,618],{"class":64},[28,716,528],{"class":38},[28,718,719],{"class":64},"\"\n",[28,721,723,726,728,730,733],{"class":30,"line":722},22,[28,724,725],{"class":425},"      class",[28,727,472],{"class":64},[28,729,618],{"class":64},[28,731,732],{"class":38},"absolute z-10 min-w-[150px] p-2 bg-white border border-gray-200 rounded-lg shadow-lg",[28,734,719],{"class":64},[28,736,738,741,743,745,748],{"class":30,"line":737},23,[28,739,740],{"class":425},"      @click.self",[28,742,472],{"class":64},[28,744,618],{"class":64},[28,746,747],{"class":38},"closePopover",[28,749,719],{"class":64},[28,751,753],{"class":30,"line":752},24,[28,754,755],{"class":64},"    >\n",[28,757,759,761,763,765,767],{"class":30,"line":758},25,[28,760,664],{"class":64},[28,762,667],{"class":421},[28,764,682],{"class":64},[28,766,667],{"class":421},[28,768,75],{"class":64},[28,770,772,774,776],{"class":30,"line":771},26,[28,773,692],{"class":64},[28,775,610],{"class":421},[28,777,75],{"class":64},[28,779,781,784,786],{"class":30,"line":780},27,[28,782,783],{"class":64},"  \u003C\u002F",[28,785,610],{"class":421},[28,787,75],{"class":64},[28,789,791,793,795],{"class":30,"line":790},28,[28,792,582],{"class":64},[28,794,599],{"class":421},[28,796,75],{"class":64},[11,798,799,800],{},"Then, we can use this component in our ",[25,801,802],{},"app.vue",[18,804,806],{"className":409,"code":805,"filename":802,"language":412,"meta":23,"style":23},"\u003Cscript setup>\nimport AppPopover from '.\u002Fcomponents\u002Fpopover.vue';\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"grid place-items-center h-screen w-screen bg-gray-100\">\n    \u003Cdiv class=\"rounded-lg bg-gray-200 w-1\u002F2 h-1\u002F2 place-items-center grid\">\n      \u003Capp-popover>\n        \u003Ctemplate #trigger> Trigger \u003C\u002Ftemplate>\n        \u003Cdiv>Popover Content\u003C\u002Fdiv>\n      \u003C\u002Fapp-popover>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[25,807,808,818,837,845,849,857,876,895,904,927,944,953,961,969],{"__ignoreMap":23},[28,809,810,812,814,816],{"class":30,"line":31},[28,811,347],{"class":64},[28,813,422],{"class":421},[28,815,426],{"class":425},[28,817,75],{"class":64},[28,819,820,822,825,828,830,833,835],{"class":30,"line":78},[28,821,434],{"class":433},[28,823,824],{"class":71}," AppPopover ",[28,826,827],{"class":433},"from",[28,829,449],{"class":64},[28,831,832],{"class":38},".\u002Fcomponents\u002Fpopover.vue",[28,834,454],{"class":64},[28,836,457],{"class":64},[28,838,839,841,843],{"class":30,"line":100},[28,840,582],{"class":64},[28,842,422],{"class":421},[28,844,75],{"class":64},[28,846,847],{"class":30,"line":121},[28,848,329],{"emptyLinePlaceholder":328},[28,850,851,853,855],{"class":30,"line":157},[28,852,347],{"class":64},[28,854,599],{"class":421},[28,856,75],{"class":64},[28,858,859,861,863,865,867,869,872,874],{"class":30,"line":183},[28,860,607],{"class":64},[28,862,610],{"class":421},[28,864,613],{"class":425},[28,866,472],{"class":64},[28,868,618],{"class":64},[28,870,871],{"class":38},"grid place-items-center h-screen w-screen bg-gray-100",[28,873,618],{"class":64},[28,875,75],{"class":64},[28,877,878,880,882,884,886,888,891,893],{"class":30,"line":209},[28,879,643],{"class":64},[28,881,610],{"class":421},[28,883,613],{"class":425},[28,885,472],{"class":64},[28,887,618],{"class":64},[28,889,890],{"class":38},"rounded-lg bg-gray-200 w-1\u002F2 h-1\u002F2 place-items-center grid",[28,892,618],{"class":64},[28,894,75],{"class":64},[28,896,897,899,902],{"class":30,"line":247},[28,898,664],{"class":64},[28,900,901],{"class":421},"app-popover",[28,903,75],{"class":64},[28,905,906,909,911,914,916,918,921,923,925],{"class":30,"line":273},[28,907,908],{"class":64},"        \u003C",[28,910,599],{"class":421},[28,912,913],{"class":64}," #",[28,915,677],{"class":425},[28,917,354],{"class":64},[28,919,920],{"class":71}," Trigger ",[28,922,582],{"class":64},[28,924,599],{"class":421},[28,926,75],{"class":64},[28,928,929,931,933,935,938,940,942],{"class":30,"line":298},[28,930,908],{"class":64},[28,932,610],{"class":421},[28,934,354],{"class":64},[28,936,937],{"class":71},"Popover Content",[28,939,582],{"class":64},[28,941,610],{"class":421},[28,943,75],{"class":64},[28,945,946,949,951],{"class":30,"line":325},[28,947,948],{"class":64},"      \u003C\u002F",[28,950,901],{"class":421},[28,952,75],{"class":64},[28,954,955,957,959],{"class":30,"line":332},[28,956,692],{"class":64},[28,958,610],{"class":421},[28,960,75],{"class":64},[28,962,963,965,967],{"class":30,"line":360},[28,964,783],{"class":64},[28,966,610],{"class":421},[28,968,75],{"class":64},[28,970,971,973,975],{"class":30,"line":589},[28,972,582],{"class":64},[28,974,599],{"class":421},[28,976,75],{"class":64},[11,978,979],{},"Now, let's see the output,",[11,981,982],{},[983,984],"img",{"alt":985,"src":986},"01-vue-popover.gif","\u002Fimg\u002F01-vue-popover.gif",[11,988,989],{},"Here, you can see when we launch the app, we see the trigger text and when we click on it, the popover menu opens. Currently, it closes we we click on the trigger again or somewhere in the content.",[11,991,992],{},"Now we can try updating the trigger text with a icon and then we can populate the popver content with the list as follows.",[18,994,996],{"className":409,"code":995,"filename":802,"language":412,"meta":23,"style":23},"\u003Cscript setup>\nimport AppPopover from '.\u002Fcomponents\u002Fpopover.vue';\n\nconst items = [\n  {\n    id: 1,\n    label: 'Edit',\n  },\n  {\n    id: 2,\n    label: 'Delete',\n  },\n];\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv class=\"grid place-items-center h-screen w-screen bg-gray-100\">\n    \u003Cdiv class=\"rounded-lg bg-gray-200 w-1\u002F2 h-1\u002F2 place-items-center grid\">\n      \u003Capp-popover>\n        \u003Ctemplate #trigger>\n          \u003Cimg\n            src=\"https:\u002F\u002Fimg.icons8.com\u002Fmaterial-rounded\u002F24\u002Fmenu-2.png\"\n            class=\"w-4 h-4 cursor-pointer\"\n          \u002F>\n        \u003C\u002Ftemplate>\n        \u003Cdiv\n          v-for=\"item in items\"\n          :key=\"item.id\"\n          class=\"hover:bg-gray-100 p-1 cursor-pointer\"\n        >\n          \u003Cspan class=\"pl-1\">\n            {{ item.label }}\n          \u003C\u002Fspan>\n        \u003C\u002Fdiv>\n      \u003C\u002Fapp-popover>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[25,997,998,1008,1024,1028,1040,1045,1059,1075,1080,1084,1095,1110,1114,1121,1129,1133,1141,1159,1177,1185,1197,1205,1219,1233,1238,1247,1253,1267,1281,1296,1302,1322,1328,1338,1347,1356,1365,1374],{"__ignoreMap":23},[28,999,1000,1002,1004,1006],{"class":30,"line":31},[28,1001,347],{"class":64},[28,1003,422],{"class":421},[28,1005,426],{"class":425},[28,1007,75],{"class":64},[28,1009,1010,1012,1014,1016,1018,1020,1022],{"class":30,"line":78},[28,1011,434],{"class":433},[28,1013,824],{"class":71},[28,1015,827],{"class":433},[28,1017,449],{"class":64},[28,1019,832],{"class":38},[28,1021,454],{"class":64},[28,1023,457],{"class":64},[28,1025,1026],{"class":30,"line":100},[28,1027,329],{"emptyLinePlaceholder":328},[28,1029,1030,1032,1035,1037],{"class":30,"line":121},[28,1031,466],{"class":425},[28,1033,1034],{"class":71}," items ",[28,1036,472],{"class":64},[28,1038,1039],{"class":71}," [\n",[28,1041,1042],{"class":30,"line":157},[28,1043,1044],{"class":64},"  {\n",[28,1046,1047,1050,1053,1056],{"class":30,"line":183},[28,1048,1049],{"class":421},"    id",[28,1051,1052],{"class":64},":",[28,1054,1055],{"class":310}," 1",[28,1057,1058],{"class":64},",\n",[28,1060,1061,1064,1066,1068,1071,1073],{"class":30,"line":209},[28,1062,1063],{"class":421},"    label",[28,1065,1052],{"class":64},[28,1067,449],{"class":64},[28,1069,1070],{"class":38},"Edit",[28,1072,454],{"class":64},[28,1074,1058],{"class":64},[28,1076,1077],{"class":30,"line":247},[28,1078,1079],{"class":64},"  },\n",[28,1081,1082],{"class":30,"line":273},[28,1083,1044],{"class":64},[28,1085,1086,1088,1090,1093],{"class":30,"line":298},[28,1087,1049],{"class":421},[28,1089,1052],{"class":64},[28,1091,1092],{"class":310}," 2",[28,1094,1058],{"class":64},[28,1096,1097,1099,1101,1103,1106,1108],{"class":30,"line":325},[28,1098,1063],{"class":421},[28,1100,1052],{"class":64},[28,1102,449],{"class":64},[28,1104,1105],{"class":38},"Delete",[28,1107,454],{"class":64},[28,1109,1058],{"class":64},[28,1111,1112],{"class":30,"line":332},[28,1113,1079],{"class":64},[28,1115,1116,1119],{"class":30,"line":360},[28,1117,1118],{"class":71},"]",[28,1120,457],{"class":64},[28,1122,1123,1125,1127],{"class":30,"line":589},[28,1124,582],{"class":64},[28,1126,422],{"class":421},[28,1128,75],{"class":64},[28,1130,1131],{"class":30,"line":594},[28,1132,329],{"emptyLinePlaceholder":328},[28,1134,1135,1137,1139],{"class":30,"line":604},[28,1136,347],{"class":64},[28,1138,599],{"class":421},[28,1140,75],{"class":64},[28,1142,1143,1145,1147,1149,1151,1153,1155,1157],{"class":30,"line":640},[28,1144,607],{"class":64},[28,1146,610],{"class":421},[28,1148,613],{"class":425},[28,1150,472],{"class":64},[28,1152,618],{"class":64},[28,1154,871],{"class":38},[28,1156,618],{"class":64},[28,1158,75],{"class":64},[28,1160,1161,1163,1165,1167,1169,1171,1173,1175],{"class":30,"line":661},[28,1162,643],{"class":64},[28,1164,610],{"class":421},[28,1166,613],{"class":425},[28,1168,472],{"class":64},[28,1170,618],{"class":64},[28,1172,890],{"class":38},[28,1174,618],{"class":64},[28,1176,75],{"class":64},[28,1178,1179,1181,1183],{"class":30,"line":689},[28,1180,664],{"class":64},[28,1182,901],{"class":421},[28,1184,75],{"class":64},[28,1186,1187,1189,1191,1193,1195],{"class":30,"line":699},[28,1188,908],{"class":64},[28,1190,599],{"class":421},[28,1192,913],{"class":64},[28,1194,677],{"class":425},[28,1196,75],{"class":64},[28,1198,1199,1202],{"class":30,"line":707},[28,1200,1201],{"class":64},"          \u003C",[28,1203,1204],{"class":421},"img\n",[28,1206,1207,1210,1212,1214,1217],{"class":30,"line":722},[28,1208,1209],{"class":425},"            src",[28,1211,472],{"class":64},[28,1213,618],{"class":64},[28,1215,1216],{"class":38},"https:\u002F\u002Fimg.icons8.com\u002Fmaterial-rounded\u002F24\u002Fmenu-2.png",[28,1218,719],{"class":64},[28,1220,1221,1224,1226,1228,1231],{"class":30,"line":737},[28,1222,1223],{"class":425},"            class",[28,1225,472],{"class":64},[28,1227,618],{"class":64},[28,1229,1230],{"class":38},"w-4 h-4 cursor-pointer",[28,1232,719],{"class":64},[28,1234,1235],{"class":30,"line":752},[28,1236,1237],{"class":64},"          \u002F>\n",[28,1239,1240,1243,1245],{"class":30,"line":758},[28,1241,1242],{"class":64},"        \u003C\u002F",[28,1244,599],{"class":421},[28,1246,75],{"class":64},[28,1248,1249,1251],{"class":30,"line":771},[28,1250,908],{"class":64},[28,1252,704],{"class":421},[28,1254,1255,1258,1260,1262,1265],{"class":30,"line":780},[28,1256,1257],{"class":425},"          v-for",[28,1259,472],{"class":64},[28,1261,618],{"class":64},[28,1263,1264],{"class":38},"item in items",[28,1266,719],{"class":64},[28,1268,1269,1272,1274,1276,1279],{"class":30,"line":790},[28,1270,1271],{"class":425},"          :key",[28,1273,472],{"class":64},[28,1275,618],{"class":64},[28,1277,1278],{"class":38},"item.id",[28,1280,719],{"class":64},[28,1282,1284,1287,1289,1291,1294],{"class":30,"line":1283},29,[28,1285,1286],{"class":425},"          class",[28,1288,472],{"class":64},[28,1290,618],{"class":64},[28,1292,1293],{"class":38},"hover:bg-gray-100 p-1 cursor-pointer",[28,1295,719],{"class":64},[28,1297,1299],{"class":30,"line":1298},30,[28,1300,1301],{"class":64},"        >\n",[28,1303,1305,1307,1309,1311,1313,1315,1318,1320],{"class":30,"line":1304},31,[28,1306,1201],{"class":64},[28,1308,28],{"class":421},[28,1310,613],{"class":425},[28,1312,472],{"class":64},[28,1314,618],{"class":64},[28,1316,1317],{"class":38},"pl-1",[28,1319,618],{"class":64},[28,1321,75],{"class":64},[28,1323,1325],{"class":30,"line":1324},32,[28,1326,1327],{"class":71},"            {{ item.label }}\n",[28,1329,1331,1334,1336],{"class":30,"line":1330},33,[28,1332,1333],{"class":64},"          \u003C\u002F",[28,1335,28],{"class":421},[28,1337,75],{"class":64},[28,1339,1341,1343,1345],{"class":30,"line":1340},34,[28,1342,1242],{"class":64},[28,1344,610],{"class":421},[28,1346,75],{"class":64},[28,1348,1350,1352,1354],{"class":30,"line":1349},35,[28,1351,948],{"class":64},[28,1353,901],{"class":421},[28,1355,75],{"class":64},[28,1357,1359,1361,1363],{"class":30,"line":1358},36,[28,1360,692],{"class":64},[28,1362,610],{"class":421},[28,1364,75],{"class":64},[28,1366,1368,1370,1372],{"class":30,"line":1367},37,[28,1369,783],{"class":64},[28,1371,610],{"class":421},[28,1373,75],{"class":64},[28,1375,1377,1379,1381],{"class":30,"line":1376},38,[28,1378,582],{"class":64},[28,1380,599],{"class":421},[28,1382,75],{"class":64},[11,1384,1385],{},"Now, let's see the output again.",[11,1387,1388],{},[983,1389],{"alt":1390,"src":1391},"02-vue-popover.gif","\u002Fimg\u002F02-vue-popover.gif",[11,1393,1394,1395,1397,1398,1401,1402,1405],{},"This mostly looks good now. But, there's one major issue. Which is, when we click outside the popover menu it should close. For this we can make use of ",[25,1396,380],{}," library ",[25,1399,1400],{},"v-on-click-outside"," directive. We can update ",[25,1403,1404],{},"popover.vue"," as follows.",[18,1407,1409],{"className":409,"code":1408,"filename":1404,"language":412,"meta":23,"style":23},"\u003Cscript setup>\n...\nimport { vOnClickOutside } from '@vueuse\u002Fcomponents';\n...\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cdiv v-on-click-outside=\"closePopover\" ...>...\u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n",[25,1410,1411,1421,1425,1447,1451,1459,1463,1471,1502],{"__ignoreMap":23},[28,1412,1413,1415,1417,1419],{"class":30,"line":31},[28,1414,347],{"class":64},[28,1416,422],{"class":421},[28,1418,426],{"class":425},[28,1420,75],{"class":64},[28,1422,1423],{"class":30,"line":78},[28,1424,357],{"class":64},[28,1426,1427,1429,1431,1434,1436,1438,1440,1443,1445],{"class":30,"line":100},[28,1428,434],{"class":433},[28,1430,437],{"class":64},[28,1432,1433],{"class":71}," vOnClickOutside",[28,1435,443],{"class":64},[28,1437,446],{"class":433},[28,1439,449],{"class":64},[28,1441,1442],{"class":38},"@vueuse\u002Fcomponents",[28,1444,454],{"class":64},[28,1446,457],{"class":64},[28,1448,1449],{"class":30,"line":121},[28,1450,357],{"class":64},[28,1452,1453,1455,1457],{"class":30,"line":157},[28,1454,582],{"class":64},[28,1456,422],{"class":421},[28,1458,75],{"class":64},[28,1460,1461],{"class":30,"line":183},[28,1462,329],{"emptyLinePlaceholder":328},[28,1464,1465,1467,1469],{"class":30,"line":209},[28,1466,347],{"class":64},[28,1468,599],{"class":421},[28,1470,75],{"class":64},[28,1472,1473,1475,1477,1480,1482,1484,1486,1488,1491,1493,1496,1498,1500],{"class":30,"line":247},[28,1474,607],{"class":64},[28,1476,610],{"class":421},[28,1478,1479],{"class":425}," v-on-click-outside",[28,1481,472],{"class":64},[28,1483,618],{"class":64},[28,1485,747],{"class":38},[28,1487,618],{"class":64},[28,1489,1490],{"class":425}," ...",[28,1492,354],{"class":64},[28,1494,1495],{"class":71},"...",[28,1497,582],{"class":64},[28,1499,610],{"class":421},[28,1501,75],{"class":64},[28,1503,1504,1506,1508],{"class":30,"line":273},[28,1505,582],{"class":64},[28,1507,599],{"class":421},[28,1509,75],{"class":64},[11,1511,1512],{},"If we take a look at the output again. We can see, now the popover menu successfully closes when we click anywhere outside it.",[11,1514,1515],{},[983,1516],{"alt":1517,"src":1518},"03-vue-popover.gif","\u002Fimg\u002F03-vue-popover.gif",[11,1520,1521],{},"So, this is how we can create custom popover component. Let me know if you run into any issues ✌️.",[1523,1524,1525],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":23,"searchDepth":78,"depth":78,"links":1527},[],"2024-09-23","In this article we'll see how we can create a custom design sytem popover component with vue 3 and tailwind css.","md","\u002Fimg\u002Fcustom-popover-with-vue.jpg",{},"\u002Fblog\u002Fcreating-popover-component-with-vue3",{"title":5,"description":1529},"blog\u002Fcreating-popover-component-with-vue3",[1537],"Web Development","kdRj2Vz15eOGrrl74469BK1GUH5OYTyJ16bEKPalw30",[1540,1545],{"title":1541,"path":1542,"stem":1543,"description":1544,"children":-1},"Creating LinkedIn Logo with TailwindCSS","\u002Fblog\u002Fcreating-linkedin-logo-with-tailwindcss","blog\u002Fcreating-linkedin-logo-with-tailwindcss","In this article, we'll see how we can create a LinkedIn logo with the help of tailwind css",{"title":1546,"path":1547,"stem":1548,"description":1549,"children":-1},"Four Different Ways to Write Functions in Javascript","\u002Fblog\u002Ffour-different-ways-to-write-functions-in-javascript","blog\u002Ffour-different-ways-to-write-functions-in-javascript","In this article we will take a look at Four Different Ways to Write Functions in Javascript",1775568345648]