A Vue 3 dropdown uses v-show="open", yet it stays invisible when open is true; what in its CSS or markup explains this?
answer
- inline style only
- restores the original inline value
- stylesheet rules still apply
- root element of a component
basics
~20 sVue's v-show only writes inline display: when true it restores the element's original inline value, often empty, so a stylesheet rule setting display: none still hides it. Placing v-show on <template> or a multi-root component also fails.
solid answer
~50 s`v-show` never forces visibility. On mount it records the element's **original inline** `display` and, when the expression is truthy, writes that value back; when falsy it writes `display: none`. If the menu's class sets `display: none` in a stylesheet, the restored inline value is usually empty, so the stylesheet still wins and the menu stays hidden. Fix it by letting the stylesheet show the element by default and leaving hiding to `v-show`, or by binding the display you want inline. Two markup causes look the same: `v-show` on a `<template>` has no element to style and is unsupported, and `v-show` on a component applies to its root, so a **multi-root** component triggers a dev warning about runtime directives on a non-element root and the directive does not work. In Vue 3.5, a bound `:style` display is used as the shown value, while `v-show`'s hidden state still wins.
go deeper
Remember that v-show only changes the inline display style and does not work on <template>.
Explain that v-show restores the original inline display when shown, so stylesheet rules still decide what that looks like.
Diagnose an invisible v-show element from DevTools: a stylesheet display: none, a <template> target or a multi-root component, and fix the right layer.
Agree who owns visibility in shared components, CSS or the directive, so stylesheet defaults and v-show never fight each other.
## How v-show actually works `v-show` is a built-in directive with a small, specific job. In the runtime it does three things: 1. **Before mount** it stores the element's current **inline** `display` value (treating an inline `none` as empty) as the "original display". 2. When the value is **falsy** it sets `el.style.display = 'none'`. 3. When the value is **truthy** it sets `el.style.display` back to that original inline value. It never touches classes or stylesheets, and it never writes `block`, `flex` or any other value of its own. The API reference puts it as: v-show sets `display` through inline styles and tries to respect the initial `display` value when the element is visible. ## Cause 1: a stylesheet already hides the element A common dropdown stylesheet looks like this: ```css .menu { display: none; } .menu.is-open { display: block; } ``` A developer then replaces the class toggle with `v-show="open"` and removes `is-open`. When `open` becomes true, `v-show` writes the original inline display, which is an empty string. An empty inline value means "no inline override", so the browser applies `.menu { display: none; }` and the menu stays hidden. Fixes, in order of preference: - Remove `display: none` from the stylesheet and let `v-show` do all the hiding. - If the element needs a specific display such as `flex`, put it in the stylesheet default (`.menu { display: flex; }`); `v-show` only overrides it with `none` while hidden. - Or bind it inline with `:style`; in Vue 3.5 a bound `display` is used as the shown value while `v-show`'s hidden state still takes priority. ## Cause 2: v-show on a <template> `<template>` renders no element, so there is no `style` to write. The guide states that `v-show` does not support `<template>`. Use `v-if` on the `<template>`, or wrap the group in a real element and put `v-show` on it. ## Cause 3: v-show on a component Putting `v-show` on a component applies the directive to the **component's root element**. That works when the component renders exactly one element root. When the component has several root nodes, or its root is a fragment or text, there is no single element to style. In development Vue warns: `Runtime directive used on component with non-element root node. The directives will not function as intended.` | Symptom | Likely cause | Fix | |---|---|---| | Hidden even when true | stylesheet `display: none` | move default display to CSS, let `v-show` hide | | No effect at all | `v-show` on `<template>` | use `v-if`, or a real wrapper element | | Dev warning, no effect | multi-root component | single-root component, or `v-show` inside it | | Wrong display when shown | expected `v-show` to set `block` | set the shown display in CSS or `:style` | ## Diagnosing it quickly - In DevTools, inspect the element: if it is present with no inline `display` while `open` is true, a stylesheet rule is hiding it. - If the element is absent entirely, the directive was never applied to an element; look for `<template>` or a multi-root component. - Check the console for the non-element-root warning in development builds. These are the failures that separate knowing "v-show toggles display" from knowing **how** it toggles it: an inline write that restores what was there before, layered under whatever the stylesheet says.
- In Vue 3, the element has `style="display: flex"` inline and `v-show`. What display does it get when shown again?`flex`. `v-show` records the original inline display before mount and writes it back whenever the value becomes truthy, so the element returns to `flex` rather than a default like `block`.
- How do you apply `v-show` to a Vue 3 component that renders two root elements?You cannot apply it to the component itself, since there is no single root element to style and Vue warns about a runtime directive on a non-element root. Wrap the component in an element carrying `v-show`, or accept a `visible` prop and apply `v-show` inside the component.
saying these in an interview costs you the question
- v-show always forces the element to display block when true.
- v-show adds or removes a CSS class to hide the element.
- v-show works on <template> like v-if does.
- v-show on any component hides it regardless of its root.