Frontend Development 8 min read

Implementing a Smooth Collapsible Panel (Accordion) in Vue Without Third‑Party UI Libraries

This article demonstrates how to build a responsive, animated collapsible side‑menu panel in Vue by using plain HTML, CSS transitions, Vue's transition component, dynamic class bindings, and a few lines of JavaScript to control height, offering a lightweight alternative to third‑party UI libraries.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Implementing a Smooth Collapsible Panel (Accordion) in Vue Without Third‑Party UI Libraries

The requirement is to create a left‑sidebar menu that expands and collapses with a smooth animation, essentially a "collapsible panel". Since third‑party component libraries cannot be used, the solution is built from scratch using Vue 3.

Basic Structure

<template>
  <div class="nav-bar-content">
    <div class="header-wrap" @click="open = !open">
      <span class="text">自动化需求计算条件输如</span>
      <span class="arrow">></span>
    </div>
    <div v-show="open" class="content">
      <p>算法及跃变计算条件</p>
      <p>空间品质判断条件</p>
      <p>需求自动计算条件</p>
      <p>通风系统</p>
    </div>
  </div>
</template>

<script setup>
const open = ref(false);
</script>

Clicking the header toggles the open variable, which controls the visibility of the content area via v-show .

Arrow Rotation Animation

<style lang="less" scoped>
.arrow {
  width: 16px;
  height: 16px;
  cursor: pointer;
  margin-left: 1px;
  transition: transform 0.2s ease;
}
.open {
  transform: rotate(90deg);
  transition: transform 0.2s ease;
}
</style>

The arrow receives the open class when the panel is expanded, rotating it 90° with a CSS transition.

Collapsible Area Animation Using Vue's Transition Component

<template>
  <div class="nav-bar-content">
    <div class="header-wrap" @click="open = !open">
      <span class="text">自动化需求计算条件输如</span>
      <span class="arrow" :class="{ open: open }">></span>
    </div>
    <div class="content-wrap">
      <Transition>
        <div v-show="open" class="content">
          ...
        </div>
      </Transition>
    </div>
  </div>
</template>

<style lang="less" scoped>
.v-enter-active, .v-leave-active { transition: transform 0.5s ease; }
.v-enter-from, .v-leave-to { transform: translateY(-100%); }
</style>

This makes the panel slide in from the top while fading, using Vue's built‑in transition classes.

Dynamic Height Animation (CSS‑Only)

<style lang="less" scoped>
.content-wrap {
  overflow: hidden;
  height: 0;
  transition: height 0.5s ease;
}
</style>

By binding the height style to open ? '300px' : 0 , the panel expands smoothly without JavaScript calculations.

Dynamic Height with JavaScript for Variable Content

<script setup>
const open = ref(false);
const contentRef = ref();
const height = ref('0');
onMounted(() => {
  height.value = contentRef.value.offsetHeight + 'px';
});
</script>

<template>
  ...
  <div class="content-wrap" :style="{ height: open ? height : 0 }">
    <div class="content" ref="contentRef">
      <slot></slot>
    </div>
  </div>
</template>

This approach measures the actual content height on mount and applies it when the panel opens, ensuring the animation works for dynamic slot content.

Conclusion

While using a third‑party UI library is the simplest way to obtain an accordion effect, the article shows that with a few lines of Vue template, CSS transitions, and optional JavaScript height calculation, developers can implement a lightweight, fully customizable collapsible panel suitable for projects that cannot depend on external component libraries.

frontendJavaScriptVueCSS TransitionUI ComponentAccordion
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.