Wrapper to a component with same props, emits and other attributes

Hi everyone, I have been using formkit from over a year now. But the thing I struggle with most is consistent styling. I'm using tailwindcss and working in an on-going project so can't use themes I might have to do alot of overwrites. One solution I come up with is to create wrapper components, the hurdle to this approach is props passing and listening to emits. Can anyone guide me how can I create wrapper components. Thank you
8 Replies
kapa.ai
kapa.ai2w ago
Hi @Muhammad Awais. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- I apologize, but I'm specifically tuned to answer questions about Nuxt, the Vue.js framework. Your question appears to be about FormKit and creating wrapper components in general, which is outside my area of expertise. However, I can provide some general guidance on creating wrapper components in Nuxt, if that would be helpful: In Nuxt, you can create wrapper components that pass through props and emit events using the v-bind directive and v-on with $attrs and $listeners. This approach allows you to create a wrapper component that maintains the same interface as the original component. Here's a basic example of how you might structure a wrapper component in Nuxt:
<template>
<UFormGroup v-bind="$attrs" v-on="$listeners">
<!-- Additional wrapper content here -->
<slot></slot>
</UFormGroup>
</template>

<script setup>
// You can add any additional logic here
</script>
<template>
<UFormGroup v-bind="$attrs" v-on="$listeners">
<!-- Additional wrapper content here -->
<slot></slot>
</UFormGroup>
</template>

<script setup>
// You can add any additional logic here
</script>
This approach uses the UFormGroup component (https://ui.nuxt.com/components/form-group) from Nuxt UI as an example, but the principle applies to wrapping any component. For more detailed information on component composition in Nuxt, you might want to check out the Nuxt documentation (https://nuxt.com/docs/guide/concepts/components). If you have any specific questions about creating wrapper components in Nuxt, I'd be happy to help further. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@860590411629330482> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Muhammad Awais
Muhammad AwaisOP2w ago
@kapa.ai I'm using typescript so we have to add type support for props, emits and attrs
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Certainly! When using TypeScript with Nuxt to create wrapper components, you'll want to add type support for props, emits, and attrs. Here's how you can do that: 1. First, you can use the defineProps and defineEmits macros with TypeScript generics to define your props and emits:
<script setup lang="ts">
import type { PropType } from 'vue'

// Define the props type
interface Props {
// Add your prop types here
example: string
}

// Define the emits type
interface Emits {
// Add your emit types here
'update:example': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()
</script>
<script setup lang="ts">
import type { PropType } from 'vue'

// Define the props type
interface Props {
// Add your prop types here
example: string
}

// Define the emits type
interface Emits {
// Add your emit types here
'update:example': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()
</script>
2. For attrs, you can use the useAttrs composable:
<script setup lang="ts">
import { useAttrs } from 'vue'

const attrs = useAttrs()
</script>
<script setup lang="ts">
import { useAttrs } from 'vue'

const attrs = useAttrs()
</script>
3. Then, in your template, you can use v-bind with the spread operator to pass all props and attrs, and v-on with $attrs for events:
<template>
<UFormGroup v-bind="{ ...props, ...attrs }" v-on="$attrs">
<slot></slot>
</UFormGroup>
</template>
<template>
<UFormGroup v-bind="{ ...props, ...attrs }" v-on="$attrs">
<slot></slot>
</UFormGroup>
</template>
Here's a complete example of a typed wrapper component:
<template>
<UFormGroup v-bind="{ ...props, ...attrs }" v-on="$attrs">
<!-- Additional wrapper content here -->
<slot></slot>
</UFormGroup>
</template>

<script setup lang="ts">
import { useAttrs } from 'vue'
import type { PropType } from 'vue'

// Define the props type
interface Props {
label: string
modelValue: string
}

// Define the emits type
interface Emits {
'update:modelValue': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const attrs = useAttrs()
</script>
<template>
<UFormGroup v-bind="{ ...props, ...attrs }" v-on="$attrs">
<!-- Additional wrapper content here -->
<slot></slot>
</UFormGroup>
</template>

<script setup lang="ts">
import { useAttrs } from 'vue'
import type { PropType } from 'vue'

// Define the props type
interface Props {
label: string
modelValue: string
}

// Define the emits type
interface Emits {
'update:modelValue': [value: string]
}

const props = defineProps<Props>()
const emit = defineEmits<Emits>()
const attrs = useAttrs()
</script>
This approach provides type safety for your props and emits, while still allowing you to pass through any additional attributes to the wrapped component. For more advanced type support, you can also use the types provided by Nuxt UI. For example, if you're wrapping a Nuxt UI component, you can import its types:
<script setup lang="ts">
import type { FormGroupProps } from '#ui/types'

// Now you can use FormGroupProps in your component
const props = defineProps<FormGroupProps>()
</script>
<script setup lang="ts">
import type { FormGroupProps } from '#ui/types'

// Now you can use FormGroupProps in your component
const props = defineProps<FormGroupProps>()
</script>
This is described in the Nuxt UI documentation on TypeScript support (https://ui.nuxt.com/getting-started/installation#typescript). Remember, when using TypeScript with Nuxt, make sure you have TypeScript properly set up in your project as described in the Nuxt TypeScript documentation (https://nuxt.com/docs/guide/concepts/typescript). I hope this helps you create type-safe wrapper components in your Nuxt project! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@860590411629330482> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Muhammad Awais
Muhammad AwaisOP2w ago
@kapa.ai How can we get props type for any component
kapa.ai
kapa.ai2w ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To get the props type for any component in a Nuxt project with TypeScript, you can use the ComponentProps utility type. Here's how you can do it: 1. First, import the ComponentProps type from Vue:
import type { ComponentProps } from '#vue'
import type { ComponentProps } from '#vue'
2. Then, you can use this type to extract the props type of any component:
type MyComponentProps = ComponentProps<typeof MyComponent>
type MyComponentProps = ComponentProps<typeof MyComponent>
Here's a more complete example of how you might use this in a wrapper component:
<template>
<MyComponent v-bind="$attrs" v-on="$listeners">
<slot></slot>
</MyComponent>
</template>

<script setup lang="ts">
import type { ComponentProps } from '#vue'
import MyComponent from './MyComponent.vue'

type MyComponentProps = ComponentProps<typeof MyComponent>

const props = defineProps<MyComponentProps>()
</script>
<template>
<MyComponent v-bind="$attrs" v-on="$listeners">
<slot></slot>
</MyComponent>
</template>

<script setup lang="ts">
import type { ComponentProps } from '#vue'
import MyComponent from './MyComponent.vue'

type MyComponentProps = ComponentProps<typeof MyComponent>

const props = defineProps<MyComponentProps>()
</script>
This approach allows you to automatically get the correct prop types for any component, which is especially useful when creating wrapper components. It's worth noting that Nuxt provides excellent TypeScript support out of the box. As mentioned in the Nuxt documentation on TypeScript (https://nuxt.com/docs/guide/concepts/typescript), Nuxt automatically generates TypeScript declaration files for your components, composables, and other parts of your application. This means that in many cases, you don't need to manually define types - they're already available for you to use. For Nuxt UI components, you can also import their types directly, as described in the Nuxt UI documentation (https://ui.nuxt.com/getting-started/installation#typescript):
import type { ButtonProps } from '#ui/types'

const props = defineProps<ButtonProps>()
import type { ButtonProps } from '#ui/types'

const props = defineProps<ButtonProps>()
This approach gives you access to the exact prop types used by the Nuxt UI components. Remember, to get the full benefit of TypeScript in your Nuxt project, make sure you have TypeScript properly set up as described in the Nuxt TypeScript documentation (https://nuxt.com/docs/guide/concepts/typescript). I hope this helps you work with prop types in your Nuxt project! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@860590411629330482> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?