#3505·shepherd

Focus automatically moves to the first input field when the Shepherd tooltip is displayed inside the Quasar dialog

Author: MuthuSelviCCreated Sep 2, 2026Updated Sep 2, 2026

https://github.com/user-attachments/assets/277c233b-3522-4d75-8481-42fa2b48115f

 const tour = new Shepherd.Tour({
    defaultStepOptions: {
      scrollTo: false,
      showCancelLink: true
    }
  });
  tour.addStep({
    id: 'test-button',
    text: 'Click this button to open the address dialog.',
    attachTo: {
      element: '[data-cy="test-button"]',
      on: 'bottom'
    },
    buttons: [
      {
        text: 'Skip',
        action: () => tour.cancel(),
        classes: 'shepherd-button-skip'
      },
      {
        text: 'Next',
        action: () => {
          document
            .querySelector('[data-cy="test-button"]')
            ?.click();

          setTimeout(() => {
            tour.next();
          }, 200);
        }
      }
    ]
  });

  tour.addStep({
    id: 'address-input',
    text: 'Enter your address here.',
    attachTo: {
      element: '[data-cy="address-input"]',
      on: 'bottom'
    },

    beforeShowPromise: () => {
      return new Promise((resolve) => {
        const checkInput = setInterval(() => {
          const input = document.querySelector(
            '[data-cy="address-input"]'
          );

          if (input) {
            clearInterval(checkInput);
            resolve();
          }
        }, 100);
      });
    },

    buttons: [
      {
        text: 'Back',
        action: () => tour.back()
      },
      {
        text: 'Next',
        action: () => tour.next()
      }
    ]
  });

  tour.addStep({
    id: 'address2-input',
    text: 'Enter your address222 here.',
    attachTo: {
      element: '[data-cy="address2-input"]',
      on: 'bottom'
    },

    beforeShowPromise: () => {
      return new Promise((resolve) => {
        const checkInput = setInterval(() => {
          const input = document.querySelector(
            '[data-cy="address2-input"]'
          );

          if (input) {
            clearInterval(checkInput);
            resolve();
          }
        }, 100);
      });
    },

    buttons: [
      {
        text: 'Back',
        action: () => tour.back()
      },
      {
        text: 'Next',
        action: () => tour.next()
      }
    ]
  });

  tour.addStep({
    id: 'pincode-input',
    text: 'Enter your pincode here.',
    attachTo: { element: '[data-cy="pincode-input"]', on: 'bottom' },
    beforeShowPromise: () => {
      return new Promise((resolve) => {
        const checkInput = setInterval(() => {
          const input = document.querySelector('[data-cy="pincode-input"]');
          if (input) {
            input.focus();
            clearInterval(checkInput);
            resolve();
          }
        }, 100);
      });
    },
    buttons: [
      {
        text: 'Back',
        action: () => tour.back()
      },
      {
        text: 'Next',
        action: () => tour.next()
      }
    ]
  });

Quasar dialog code:

<q-dialog v-model="prompt" no-focus
            persistent>
    <q-card data-cy="address-dialog"
            style="min-width: 350px">
      <q-card-section>
        <div class="text-h6">Your address</div>
      </q-card-section>

      <q-card-section class="q-pt-none">
        <q-input data-cy="address-input"
                 dense
                 v-model="address" />
        <q-input data-cy="address2-input"
                 dense
                 v-model="address2" />
        <q-input data-cy="pincode-input"
                 dense
                 v-model="pincode" />
      </q-card-section>

      <q-card-actions align="right" class="text-primary">
        <q-btn data-cy="address-cancel"
               flat
               label="Cancel"
               v-close-popup />

        <q-btn data-cy="address-add"
               flat
               label="Add address"
               v-close-popup />
      </q-card-actions>
    </q-card>
  </q-dialog>

The Pincode input is initially focused when the Shepherd tooltip is displayed, but the focus is then automatically moved to the first input field.