Skip to content

[Feature Request] Expansion Panel animation support #243

@J-Sek

Description

@J-Sek

It took me some time to get the demo below working. It consists of renderless + <Transition> + 2x <div>.

At the very least the docs could just include it, as AI is unfortunately no able to figure it out - better to have a working reference.

Nice to have: similar expand transition in Treeview

<script setup lang="ts">
import { ExpansionPanel } from '@vuetify/v0'
import { shallowRef } from 'vue'

const model = shallowRef<string>('')

const tableData = Array.from({ length: 20 }, (_, i) => ({
  id: i + 1,
  name: `Item ${i + 1}`,
  email: `user${i + 1}@example.com`,
  status: i % 3 === 0 ? 'Active' : i % 3 === 1 ? 'Pending' : 'Inactive',
}))
</script>

<template>
  <ExpansionPanel.Group v-model="model"
    class="border border-divider rounded-lg border-solid overflow-hidden divide-y divide-divider">
    <ExpansionPanel.Root v-for="i in 3" :value="`panel-${i}`">
      <ExpansionPanel.Activator
        class="w-full px-4 py-3 border-none flex items-center gap-3 text-left cursor-pointer bg-surface hover:bg-surface-tint">

        <ExpansionPanel.Cue
          class="inline-flex items-center justify-center w-5 text-sm text-on-surface opacity-60 data-[state=open]:text-primary transition-transform duration-200 data-[state=open]:rotate-90">
          ▶
        </ExpansionPanel.Cue>
        <span class="font-medium text-on-surface">Panel {{ i }} - Product Data</span>
      </ExpansionPanel.Activator>

      <ExpansionPanel.Content renderless #default="{ isSelected }">
        <Transition name="expand">
          <div v-if="isSelected">
            <div class="p-4">
              <table class="w-full text-sm border-collapse">
                <thead>
                  <tr class="border-b border-divider">
                    <th class="text-left p-2 font-semibold text-on-surface">ID</th>
                    <th class="text-left p-2 font-semibold text-on-surface">Product</th>
                    <th class="text-left p-2 font-semibold text-on-surface">SKU</th>
                    <th class="text-left p-2 font-semibold text-on-surface">Price</th>
                  </tr>
                </thead>
                <tbody>
                  <tr v-for="row in tableData" :key="row.id" class="border-b border-divider hover:bg-surface-tint">
                    <td class="p-2 text-on-surface">{{ row.id }}</td>
                    <td class="p-2 text-on-surface">Product {{ row.id }}</td>
                    <td class="p-2 text-on-surface">SKU-{{ String(row.id).padStart(5, '0') }}</td>
                    <td class="p-2 text-on-surface">${{ (row.id * 12.99).toFixed(2) }}</td>
                  </tr>
                </tbody>
              </table>
            </div>
          </div>
        </Transition>
      </ExpansionPanel.Content>
    </ExpansionPanel.Root>
  </ExpansionPanel.Group>
</template>

<style>
.expand-enter-active,
.expand-leave-active {
  transition: max-height 0.3s ease;
  interpolate-size: allow-keywords;
  overflow: hidden;
}

.expand-enter-from,
.expand-leave-to {
  max-height: 0;
}

.expand-leave-from,
.expand-enter-to {
  max-height: max-content;
}
</style>

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions