Vue Collapsed
Vue Collapsed is a Vue 3 component that provides dynamic CSS height transitions, enabling smooth expansion and collapse animations for elements, typically used in accordions, collapsible panels, or reveal sections. It intelligently handles transitions to and from `height: auto`, which is traditionally challenging to animate natively with CSS transitions. The current stable version is 1.3.5, with frequent patch and minor releases addressing various edge cases, browser compatibility, and performance improvements, indicating an active development cadence. A key differentiator is its automatic calculation of optimal transition durations (`--vc-auto-duration`), which adapts to the element's height for a natural feel. It also offers robust support for custom CSS transitions and detailed animation control via `data-collapse` attributes, allowing for multi-property animations beyond just height. Furthermore, it includes specific optimizations and fixes for Server-Side Rendering (SSR) environments, aiming to minimize layout shifts and ensure consistent visual states on initial page load.
Common errors
-
TypeError: Cannot read properties of null (reading 'style')
cause The `Collapse` component's internal references could become null if the element was removed from the DOM before its animation completed, leading to a runtime error.fixUpdate to `vue-collapsed@1.3.5` or a newer version which includes a fix for this unmount-during-transition error. -
Hydration children mismatch warning or component visibly jumps/flickers on SSR initial render.
cause Older versions of `vue-collapsed` had an SSR layout shift bug where the component would initially render as expanded even if `when` was false, then correct itself client-side.fixUpdate to `vue-collapsed@1.3.0` or higher to utilize the SSR layout shift fix, ensuring the component renders correctly from the start. -
Collapse animation not working, has an infinite duration, or incorrect height calculated on iOS or when the element is initially hidden (e.g., `display: none`).
cause Specific browser environments (like iOS) or initial CSS states (`display: none`) could prevent the automatic duration calculation from working correctly.fixUpgrade to `vue-collapsed@1.2.8` (for iOS) or `vue-collapsed@1.2.7` (for hidden containers) or newer versions to resolve these environment-specific animation issues.
Warnings
- gotcha Prior to v1.3.0, applications using Server-Side Rendering (SSR) might experience an initial layout shift where the collapsed element is temporarily displayed as expanded before JavaScript loads and the component hydrates.
- breaking Versions prior to 1.3.5 could throw a TypeError if the collapse element was unmounted from the DOM before its transition animation had completed.
- gotcha On iOS devices (versions <1.2.8) or when the Collapse component was mounted within a container with `display: none` (versions <1.2.7), the automatic duration calculation (`getAutoDuration`) could return `Infinity`, leading to non-existent or incorrect height transitions.
- gotcha Firefox 124+ required an additional condition check for undefined CSS transitions, which was not present in versions prior to 1.3.1, potentially causing unexpected transition behavior.
Install
-
npm install vue-collapsed -
yarn add vue-collapsed -
pnpm add vue-collapsed
Imports
- Collapse
import Collapse from 'vue-collapsed'
import { Collapse } from 'vue-collapsed'
Quickstart
<script setup lang="ts">
import { ref } from 'vue'
import { Collapse } from 'vue-collapsed'
const isExpanded = ref(false)
const longContent = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. '.repeat(5)
</script>
<template>
<button @click="isExpanded = !isExpanded">Toggle Collapse</button>
<Collapse :when="isExpanded">
<p>{{ longContent }}</p>
</Collapse>
</template>
<style>
/* Optional: Custom transition example */
.collapsed-area {
transition: height 300ms ease-out;
}
</template>