[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"\u002Fblog\u002Ftailwind-css-4-hover-on-touch-device":3,"$fnWpB3wSyWpfPWLN5_GJ7LLv6ljOPsUhovl36l1vnYkI":744,"i-local-icon:calendar-days":747,"i-local-icon:tag":751,"i-local-icon:eye":753},{"id":4,"title":5,"body":6,"categories_slug":733,"comment_count":735,"date_published":736,"description":737,"extension":738,"meta":739,"navigation":82,"path":740,"seo":741,"stem":742,"__hash__":743},"content\u002Fblog\u002F20.tailwind-css-4-hover-on-touch-device.md","Handling hover states on mobile and touch devices in Tailwind CSS 4",{"type":7,"value":8,"toc":728},"minimark",[9,13,18,23,27,33,48,52,59,112,125,129,132,137,140,147,150,155,705,708,724],[10,11,5],"h1",{"id":12},"handling-hover-states-on-mobile-and-touch-devices-in-tailwind-css-4",[14,15],"meta-card",{":categories":16,":date":17},"categories_slug","date_published",[19,20,22],"h2",{"id":21},"overview-the-change-in-tailwind-css-4","Overview - The change in Tailwind CSS 4",[24,25,26],"p",{},"Tailwind CSS 4 introduced a breaking change to how hover states work. As stated in their upgrade guide:",[28,29,30],"blockquote",{},[24,31,32],{},"In v4 we've updated the hover variant to only apply when the primary input device supports hover. This can create problems if you've built your site in a way that depends on touch devices triggering hover on tap.",[24,34,35,39,40,44,45,47],{},[36,37,38],"strong",{},"What this means:"," Hover effects now only work on devices with true hover capability (like desktops with mice), not on touch devices where ",[41,42,43],"code",{},"hover"," was previously triggered by tapping. This can cause issues on devices such as tablets, where for example, you have a menu with dropdown items that relied on ",[41,46,43],{}," to open the menu.",[19,49,51],{"id":50},"option-1-quick-fix-restore-version-3-behavior","Option 1: Quick fix - restore version 3 behavior",[24,53,54,55,58],{},"To set the behaviour back to how it was in Tailwind CSS version 3, just add the following ",[41,56,57],{},"@custom-variant"," to your global CSS file:",[60,61,66],"pre",{"className":62,"code":63,"language":64,"meta":65,"style":65},"language-css shiki shiki-themes github-dark","\u002F* Tailwind CSS 4 - eg. main.css *\u002F\n\n@import \"tailwindcss\";\n\n@custom-variant hover (&:hover);\n","css","",[41,67,68,77,84,99,104],{"__ignoreMap":65},[69,70,73],"span",{"class":71,"line":72},"line",1,[69,74,76],{"class":75},"sAwPA","\u002F* Tailwind CSS 4 - eg. main.css *\u002F\n",[69,78,80],{"class":71,"line":79},2,[69,81,83],{"emptyLinePlaceholder":82},true,"\n",[69,85,87,91,95],{"class":71,"line":86},3,[69,88,90],{"class":89},"snl16","@import",[69,92,94],{"class":93},"sU2Wk"," \"tailwindcss\"",[69,96,98],{"class":97},"s95oV",";\n",[69,100,102],{"class":71,"line":101},4,[69,103,83],{"emptyLinePlaceholder":82},[69,105,107,109],{"class":71,"line":106},5,[69,108,57],{"class":89},[69,110,111],{"class":97}," hover (&:hover);\n",[24,113,114,117,118,121,124],{},[36,115,116],{},"Pros:"," Immediate fix, maintains existing functionality",[119,120],"br",{},[36,122,123],{},"Cons:"," Doesn't follow modern best practices, may cause \"stuck\" hover states",[19,126,128],{"id":127},"option-2-more-complex-solution","Option 2: More complex solution",[24,130,131],{},"According to the Tailwind documentation:",[28,133,134],{},[24,135,136],{},"Generally though we recommend treating hover functionality as an enhancement, and not depending on it for your site to work since touch devices don't truly have the ability to hover.",[24,138,139],{},"To follow Tailwind CSS v4’s recommendation of treating hover as a progressive enhancement, you should design your UI to work without hover effects, and only use them to enhance interactivity where supported.",[24,141,142,143,146],{},"Tailwind v4 introduced a smarter default behavior: it only generates hover styles inside a ",[41,144,145],{},"@media (hover: hover)"," block — which means they’ll only apply on devices that support hover (like a desktop). This prevents “stuck” hover states on touch devices like iPads.",[24,148,149],{},"For example, dropdown menus should be designed to open on click\u002Ftap by default, and optionally enhanced with hover on desktop.",[24,151,152],{},[36,153,154],{},"A Vue JS example:",[60,156,160],{"className":157,"code":158,"language":159,"meta":65,"style":65},"language-javascript shiki shiki-themes github-dark","\n\u003Ctemplate>\n  \u003Cdiv\n    ref=\"dropdownRef\"\n    class=\"relative inline-block text-left\"\n    @mouseenter=\"handleMouseEnter\"\n    @mouseleave=\"handleMouseLeave\"\n  >\n    \u003Cbutton\n      @click=\"toggle\"\n      class=\"inline-flex justify-center w-full px-4 py-2 bg-gray-200 rounded-md hover:bg-gray-300\"\n    >\n      Menu\n    \u003C\u002Fbutton>\n    \u003Cdiv\n      v-if=\"open\"\n      class=\"absolute left-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-10\"\n    >\n      \u003Ca href=\"#\" class=\"block px-4 py-2 hover:bg-gray-100\">Item 1\u003C\u002Fa>\n      \u003Ca href=\"#\" class=\"block px-4 py-2 hover:bg-gray-100\">Item 2\u003C\u002Fa>\n      \u003Ca href=\"#\" class=\"block px-4 py-2 hover:bg-gray-100\">Item 3\u003C\u002Fa>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nimport { ref, onMounted, onBeforeUnmount } from 'vue'\n\nconst open = ref(false)\nconst dropdownRef = ref(null)\n\nconst toggle = () => {\n  open.value = !open.value\n}\n\n\u002F\u002F Close on outside click\nconst handleClickOutside = (event) => {\n  if (dropdownRef.value && !dropdownRef.value.contains(event.target)) {\n    open.value = false\n  }\n}\n\nonMounted(() => {\n  document.addEventListener('click', handleClickOutside)\n})\n\nonBeforeUnmount(() => {\n  document.removeEventListener('click', handleClickOutside)\n})\n\n\u002F\u002F Optional hover enhancement\nconst canHover = window.matchMedia('(hover: hover)').matches\n\nconst handleMouseEnter = () => {\n  if (canHover) open.value = true\n}\n\nconst handleMouseLeave = () => {\n  if (canHover) open.value = false\n}\n\u003C\u002Fscript>\n","javascript",[41,161,162,166,178,186,198,208,215,221,227,236,242,253,259,265,276,283,294,304,309,341,367,393,403,413,423,428,441,447,452,458,464,469,475,489,495,500,506,512,535,547,553,558,563,569,587,593,598,604,618,623,628,634,640,645,651,664,669,674,680,691,696],{"__ignoreMap":65},[69,163,164],{"class":71,"line":72},[69,165,83],{"emptyLinePlaceholder":82},[69,167,168,171,175],{"class":71,"line":79},[69,169,170],{"class":97},"\u003C",[69,172,174],{"class":173},"s4JwU","template",[69,176,177],{"class":97},">\n",[69,179,180,183],{"class":71,"line":86},[69,181,182],{"class":97},"  \u003C",[69,184,185],{"class":173},"div\n",[69,187,188,192,195],{"class":71,"line":101},[69,189,191],{"class":190},"svObZ","    ref",[69,193,194],{"class":89},"=",[69,196,197],{"class":93},"\"dropdownRef\"\n",[69,199,200,203,205],{"class":71,"line":106},[69,201,202],{"class":190},"    class",[69,204,194],{"class":89},[69,206,207],{"class":93},"\"relative inline-block text-left\"\n",[69,209,211],{"class":71,"line":210},6,[69,212,214],{"class":213},"s6RL2","    @mouseenter=\"handleMouseEnter\"\n",[69,216,218],{"class":71,"line":217},7,[69,219,220],{"class":213},"    @mouseleave=\"handleMouseLeave\"\n",[69,222,224],{"class":71,"line":223},8,[69,225,226],{"class":97},"  >\n",[69,228,230,233],{"class":71,"line":229},9,[69,231,232],{"class":97},"    \u003C",[69,234,235],{"class":173},"button\n",[69,237,239],{"class":71,"line":238},10,[69,240,241],{"class":213},"      @click=\"toggle\"\n",[69,243,245,248,250],{"class":71,"line":244},11,[69,246,247],{"class":190},"      class",[69,249,194],{"class":89},[69,251,252],{"class":93},"\"inline-flex justify-center w-full px-4 py-2 bg-gray-200 rounded-md hover:bg-gray-300\"\n",[69,254,256],{"class":71,"line":255},12,[69,257,258],{"class":97},"    >\n",[69,260,262],{"class":71,"line":261},13,[69,263,264],{"class":97},"      Menu\n",[69,266,268,271,274],{"class":71,"line":267},14,[69,269,270],{"class":97},"    \u003C\u002F",[69,272,273],{"class":173},"button",[69,275,177],{"class":97},[69,277,279,281],{"class":71,"line":278},15,[69,280,232],{"class":97},[69,282,185],{"class":173},[69,284,286,289,291],{"class":71,"line":285},16,[69,287,288],{"class":190},"      v-if",[69,290,194],{"class":89},[69,292,293],{"class":93},"\"open\"\n",[69,295,297,299,301],{"class":71,"line":296},17,[69,298,247],{"class":190},[69,300,194],{"class":89},[69,302,303],{"class":93},"\"absolute left-0 mt-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 z-10\"\n",[69,305,307],{"class":71,"line":306},18,[69,308,258],{"class":97},[69,310,312,315,318,321,323,326,329,331,334,337,339],{"class":71,"line":311},19,[69,313,314],{"class":97},"      \u003C",[69,316,317],{"class":173},"a",[69,319,320],{"class":190}," href",[69,322,194],{"class":89},[69,324,325],{"class":93},"\"#\"",[69,327,328],{"class":190}," class",[69,330,194],{"class":89},[69,332,333],{"class":93},"\"block px-4 py-2 hover:bg-gray-100\"",[69,335,336],{"class":97},">Item 1\u003C\u002F",[69,338,317],{"class":173},[69,340,177],{"class":97},[69,342,344,346,348,350,352,354,356,358,360,363,365],{"class":71,"line":343},20,[69,345,314],{"class":97},[69,347,317],{"class":173},[69,349,320],{"class":190},[69,351,194],{"class":89},[69,353,325],{"class":93},[69,355,328],{"class":190},[69,357,194],{"class":89},[69,359,333],{"class":93},[69,361,362],{"class":97},">Item 2\u003C\u002F",[69,364,317],{"class":173},[69,366,177],{"class":97},[69,368,370,372,374,376,378,380,382,384,386,389,391],{"class":71,"line":369},21,[69,371,314],{"class":97},[69,373,317],{"class":173},[69,375,320],{"class":190},[69,377,194],{"class":89},[69,379,325],{"class":93},[69,381,328],{"class":190},[69,383,194],{"class":89},[69,385,333],{"class":93},[69,387,388],{"class":97},">Item 3\u003C\u002F",[69,390,317],{"class":173},[69,392,177],{"class":97},[69,394,396,398,401],{"class":71,"line":395},22,[69,397,270],{"class":97},[69,399,400],{"class":173},"div",[69,402,177],{"class":97},[69,404,406,409,411],{"class":71,"line":405},23,[69,407,408],{"class":97},"  \u003C\u002F",[69,410,400],{"class":173},[69,412,177],{"class":97},[69,414,416,419,421],{"class":71,"line":415},24,[69,417,418],{"class":97},"\u003C\u002F",[69,420,174],{"class":173},[69,422,177],{"class":97},[69,424,426],{"class":71,"line":425},25,[69,427,83],{"emptyLinePlaceholder":82},[69,429,431,433,436,439],{"class":71,"line":430},26,[69,432,170],{"class":97},[69,434,435],{"class":173},"script",[69,437,438],{"class":190}," setup",[69,440,177],{"class":97},[69,442,444],{"class":71,"line":443},27,[69,445,446],{"class":97},"import { ref, onMounted, onBeforeUnmount } from 'vue'\n",[69,448,450],{"class":71,"line":449},28,[69,451,83],{"emptyLinePlaceholder":82},[69,453,455],{"class":71,"line":454},29,[69,456,457],{"class":97},"const open = ref(false)\n",[69,459,461],{"class":71,"line":460},30,[69,462,463],{"class":97},"const dropdownRef = ref(null)\n",[69,465,467],{"class":71,"line":466},31,[69,468,83],{"emptyLinePlaceholder":82},[69,470,472],{"class":71,"line":471},32,[69,473,474],{"class":97},"const toggle = () => {\n",[69,476,478,481,483,486],{"class":71,"line":477},33,[69,479,480],{"class":97},"  open.value ",[69,482,194],{"class":89},[69,484,485],{"class":89}," !",[69,487,488],{"class":97},"open.value\n",[69,490,492],{"class":71,"line":491},34,[69,493,494],{"class":97},"}\n",[69,496,498],{"class":71,"line":497},35,[69,499,83],{"emptyLinePlaceholder":82},[69,501,503],{"class":71,"line":502},36,[69,504,505],{"class":97},"\u002F\u002F Close on outside click\n",[69,507,509],{"class":71,"line":508},37,[69,510,511],{"class":97},"const handleClickOutside = (event) => {\n",[69,513,515,518,521,524,526,529,532],{"class":71,"line":514},38,[69,516,517],{"class":190},"  if",[69,519,520],{"class":97}," (dropdownRef.value ",[69,522,523],{"class":89},"&&",[69,525,485],{"class":89},[69,527,528],{"class":97},"dropdownRef.value.",[69,530,531],{"class":190},"contains",[69,533,534],{"class":97},"(event.target)) {\n",[69,536,538,541,543],{"class":71,"line":537},39,[69,539,540],{"class":97},"    open.value ",[69,542,194],{"class":89},[69,544,546],{"class":545},"sDLfK"," false\n",[69,548,550],{"class":71,"line":549},40,[69,551,552],{"class":97},"  }\n",[69,554,556],{"class":71,"line":555},41,[69,557,494],{"class":97},[69,559,561],{"class":71,"line":560},42,[69,562,83],{"emptyLinePlaceholder":82},[69,564,566],{"class":71,"line":565},43,[69,567,568],{"class":97},"onMounted(() => {\n",[69,570,572,575,578,581,584],{"class":71,"line":571},44,[69,573,574],{"class":97},"  document.",[69,576,577],{"class":190},"addEventListener",[69,579,580],{"class":97},"(",[69,582,583],{"class":93},"'click'",[69,585,586],{"class":97},", handleClickOutside)\n",[69,588,590],{"class":71,"line":589},45,[69,591,592],{"class":97},"})\n",[69,594,596],{"class":71,"line":595},46,[69,597,83],{"emptyLinePlaceholder":82},[69,599,601],{"class":71,"line":600},47,[69,602,603],{"class":97},"onBeforeUnmount(() => {\n",[69,605,607,609,612,614,616],{"class":71,"line":606},48,[69,608,574],{"class":97},[69,610,611],{"class":190},"removeEventListener",[69,613,580],{"class":97},[69,615,583],{"class":93},[69,617,586],{"class":97},[69,619,621],{"class":71,"line":620},49,[69,622,592],{"class":97},[69,624,626],{"class":71,"line":625},50,[69,627,83],{"emptyLinePlaceholder":82},[69,629,631],{"class":71,"line":630},51,[69,632,633],{"class":97},"\u002F\u002F Optional hover enhancement\n",[69,635,637],{"class":71,"line":636},52,[69,638,639],{"class":97},"const canHover = window.matchMedia('(hover: hover)').matches\n",[69,641,643],{"class":71,"line":642},53,[69,644,83],{"emptyLinePlaceholder":82},[69,646,648],{"class":71,"line":647},54,[69,649,650],{"class":97},"const handleMouseEnter = () => {\n",[69,652,654,656,659,661],{"class":71,"line":653},55,[69,655,517],{"class":190},[69,657,658],{"class":97}," (canHover) open.value ",[69,660,194],{"class":89},[69,662,663],{"class":545}," true\n",[69,665,667],{"class":71,"line":666},56,[69,668,494],{"class":97},[69,670,672],{"class":71,"line":671},57,[69,673,83],{"emptyLinePlaceholder":82},[69,675,677],{"class":71,"line":676},58,[69,678,679],{"class":97},"const handleMouseLeave = () => {\n",[69,681,683,685,687,689],{"class":71,"line":682},59,[69,684,517],{"class":190},[69,686,658],{"class":97},[69,688,194],{"class":89},[69,690,546],{"class":545},[69,692,694],{"class":71,"line":693},60,[69,695,494],{"class":97},[69,697,699,701,703],{"class":71,"line":698},61,[69,700,418],{"class":97},[69,702,435],{"class":173},[69,704,177],{"class":97},[24,706,707],{},"The example code above:",[709,710,711,715,718,721],"ul",{},[712,713,714],"li",{},"Opens the dropdown on click, which works on all devices.",[712,716,717],{},"Enhances with hover on desktops\u002Flaptops.",[712,719,720],{},"Prevents dropdowns from getting \"stuck\" open on iPads.",[712,722,723],{},"Click outside to close improves usability.",[725,726,727],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}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 pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .s6RL2, html code.shiki .s6RL2{--shiki-default:#FDAEB7;--shiki-default-font-style:italic}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":65,"searchDepth":79,"depth":79,"links":729},[730,731,732],{"id":21,"depth":79,"text":22},{"id":50,"depth":79,"text":51},{"id":127,"depth":79,"text":128},[64,734],"tailwind",null,"2025-07-09","Tailwind CSS v4 has been updated so that the hover variant only applies when the primary input device supports hover.  Options on how to solve the issues this presents.","md",{},"\u002Fblog\u002Ftailwind-css-4-hover-on-touch-device",{"title":5,"description":737},"blog\u002F20.tailwind-css-4-hover-on-touch-device","jZmzwcoo-CqlAJ4mtnNQmo51vaNOI_q1TNZb5zciJRE",[745],{"id":491,"name":740,"count":746},4066,{"left":748,"top":748,"width":415,"height":415,"rotate":748,"vFlip":749,"hFlip":749,"body":750},0,false,"\u003Cpath\n    fill=\"none\"\n    stroke=\"currentColor\"\n    stroke-linecap=\"round\"\n    stroke-linejoin=\"round\"\n    stroke-width=\"1.5\"\n    d=\"M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5m-9-6h.008v.008H12zM12 15h.008v.008H12zm0 2.25h.008v.008H12zM9.75 15h.008v.008H9.75zm0 2.25h.008v.008H9.75zM7.5 15h.008v.008H7.5zm0 2.25h.008v.008H7.5zm6.75-4.5h.008v.008h-.008zm0 2.25h.008v.008h-.008zm0 2.25h.008v.008h-.008zm2.25-4.5h.008v.008H16.5zm0 2.25h.008v.008H16.5z\" \u002F>",{"left":748,"top":748,"width":415,"height":415,"rotate":748,"vFlip":749,"hFlip":749,"body":752},"\u003Cg\n    fill=\"none\"\n    stroke=\"currentColor\"\n    stroke-linecap=\"round\"\n    stroke-linejoin=\"round\"\n    stroke-width=\"1.5\">\n    \u003Cpath\n      d=\"M9.568 3H5.25A2.25 2.25 0 0 0 3 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.1 18.1 0 0 0 5.224-5.223c.54-.827.368-1.908-.33-2.607l-9.583-9.58A2.25 2.25 0 0 0 9.568 3\" \u002F>\n    \u003Cpath d=\"M6 6h.008v.008H6z\" \u002F>\n  \u003C\u002Fg>",{"left":748,"top":748,"width":415,"height":415,"rotate":748,"vFlip":749,"hFlip":749,"body":754},"\u003Cg\n    fill=\"none\"\n    stroke=\"currentColor\"\n    stroke-linecap=\"round\"\n    stroke-linejoin=\"round\"\n    stroke-width=\"1.5\">\n    \u003Cpath\n      d=\"M2.036 12.322a1 1 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178c.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178\" \u002F>\n    \u003Cpath d=\"M15 12a3 3 0 1 1-6 0a3 3 0 0 1 6 0\" \u002F>\n  \u003C\u002Fg>"]