SortableJS/Vue.Draggable · error · Error

Transition-group inside component is not supported. Please a

Error message

Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ${this.getTag()}

What it means

vuedraggable throws this in mounted() when it detects 'non-functional component mode' (the rendered root element's node name differs from the tag prop) AND a transition mode is in use. In that mode Sortable cannot properly hook the transition-group internals, so transitions plus a custom tag/component are rejected. You must either remove the transition-group usage or align the tag prop so the component renders a real element.

Source

Thrown at src/vuedraggable.js:202

    if (this.element !== "div") {
      console.warn(
        "Element props is deprecated please use tag props instead. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#element-props"
      );
    }

    if (this.options !== undefined) {
      console.warn(
        "Options props is deprecated, add sortable options directly as vue.draggable item, or use v-bind. See https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#options-props"
      );
    }
  },

  mounted() {
    this.noneFunctionalComponentMode =
      this.getTag().toLowerCase() !== this.$el.nodeName.toLowerCase() &&
      !this.getIsFunctional();
    if (this.noneFunctionalComponentMode && this.transitionMode) {
      throw new Error(
        `Transition-group inside component is not supported. Please alter tag value or remove transition-group. Current tag value: ${this.getTag()}`
      );
    }
    const optionsAdded = {};
    eventsListened.forEach(elt => {
      optionsAdded["on" + elt] = delegateAndEmit.call(this, elt);
    });

    eventsToEmit.forEach(elt => {
      optionsAdded["on" + elt] = emit.bind(this, elt);
    });

    const attributes = Object.keys(this.$attrs).reduce((res, key) => {
      res[camelize(key)] = this.$attrs[key];
      return res;
    }, {});

    const options = Object.assign({}, this.options, attributes, optionsAdded, {

View on GitHub (pinned to 431db153bf)

Solutions

  1. Set tag to a plain HTML element (e.g. tag='div') and remove the transition-group/component-data transition mode
  2. If you need animations, use tag='transition-group' with :component-data so the root matches the transition-group
  3. Remove the <transition-group> wrapper entirely and animate via CSS on the draggable container
  4. Check getIsFunctional(): make sure you are not wrapping draggable in a component whose $el is a different node than tag

Example fix

// before
<draggable tag="transition-group" :component-data="{ tag: 'ul', name: 'flip-list' }">
  <li v-for="item in list" :key="item.id">{{ item.name }}</li>
</draggable>

// after (plain element, no transition-group)
<draggable tag="ul">
  <li v-for="item in list" :key="item.id">{{ item.name }}</li>
</draggable>
Defensive patterns

Strategy: validation

Validate before calling

function assertTransitionCompatible(draggableVm) {
  if (!draggableVm) return;
  const tag = String(draggableVm.tag || 'div').toLowerCase();
  const root = draggableVm.$el && draggableVm.$el.nodeName.toLowerCase();
  if (tag !== root && !draggableVm.getIsFunctional?.() && draggableVm.transitionMode) {
    throw new Error(`draggable: tag '${tag}' does not match rendered root '${root}' while using transition-group; use tag='transition-group' or remove transitions`);
  }
}

Type guard

function isPlainElementTag(tag) {
  return typeof tag === 'string' && /^[a-z][a-z0-9-]*$/.test(tag) && !['transition-group','transition'].includes(tag);
}

Try / catch

// wrap component creation/mount if rendering dynamically
try {
  mountDraggable(props);
} catch (e) {
  if (String(e.message).includes('Transition-group inside component is not supported')) {
    console.error('Fix draggable config: use tag="transition-group" or drop transition-group');
  } else { throw e; }
}

Prevention

When it happens

Trigger: Using <draggable tag='transition-group'> or a custom component tag whose rendered root differs from getTag() while also enabling transition mode (e.g. passing a <transition-group> as the tag/child in Vue 2 vuedraggable). Example: <draggable tag='my-component' :component-data='{...transition-group props...}'>.

Common situations: Migrating lists that animate on reorder; copying Vue 2 transition-group examples but wrapping them in a wrapper component; setting tag to a component name (kebab-case) instead of a plain HTML element so $el.nodeName doesn't match.

Related errors


AI-assisted analysis of SortableJS/Vue.Draggable@431db153bf (2026-09-02). Data as JSON: /api/errors/8168f5f893ac9315. Report an issue: GitHub.