'How to correctly pass a v-model down to a Quasar q-input base component?

I am using Quasar to build my Vue app and I want to create a base component (a.k.a. presentational, dumb, or pure component) using q-input.

I have a created a SFC named VInput.vue as my base component, it looks like this:

<template>
  <q-input
    outlined
    class="q-mb-md"
    hide-bottom-space
  />
</template>

Then I created a SFC named TestForm.vue that looks like this:

<template>
  <q-form>
    <v-input label="Email" v-model="email" />
  </q-form>
</template>

<script setup lang="ts">
import VInput from './VInput.vue';
import { ref } from 'vue';
const email = ref('[email protected]');
</script>

The label="Email" v-model="email" parts are passed down to my VInput.vue base component and correctly rendered on the page.

But there is a typescript error on q-input of the VInput.vue base component because q-input requires a v-model:

`Type '{ outlined: true; class: string; hideBottomSpace: true; "hide-bottom-space": boolean; }' is not assignable to type 'IntrinsicAttributes & VNodeProps & AllowedComponentProps & ComponentCustomProps & QInputProps'.`
`Property 'modelValue' is missing in type '{ outlined: true; class: string; hideBottomSpace: true; "hide-bottom-space": boolean; }' but required in type 'QInputProps'.ts(2322)`.

So how do I code the VInput.vue base component without knowing the v-model value head of time?

I have come up with the below solution, which seems to work because I think the v-model passed down is overiding the base component v-model.

But I wanted to ask to make sure I wasn't screwing something up.

Is this the correct way of doing things? It seems hacky.

<template>
  <q-input v-model="inputText" outlined class="q-mb-md" hide-bottom-space />
</template>

<script setup lang="ts">
const inputText = '';
</script>


Solution 1:[1]

I found a couple of solutions:

Solution 1

It involves splitting the v-model into it seperate parts (:model-value and @update:model-value, and then passing in the text value as a prop.

Base component VInput.vue:

    <template>
      <q-input
        outlined
        class="q-mb-md"
        hide-bottom-space
        :model-value="text"
        @update:model-value="(value) => emit('update:text', value)"
      />
    </template>
    
    <script setup lang="ts">
    defineProps({
      text: {
        required: false,
        type: String,
      },
    });
    const emit = defineEmits(['update:text']);
    </script>

Solution 2

Extracting the prop and using toRef on it.

    <template>
      <q-input outlined class="q-mb-md" hide-bottom-space v-model="textProp" />
    </template>
    
    <script setup lang="ts">
    import { toRef } from 'vue';
    const props = defineProps({
      text: {
        required: false,
        type: String,
        default: '',
      },
    });
    const textProp = toRef(props, 'text');
    </script>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 David Wolf