I have a simple FormComponent:
<template>
<form>
<fieldset>
<slot />
</fieldset>
<span v-if="!isEditing" @click="edit()">Edit</span>
</form>
</template>
<script>
export default {
data () {
return {
isEditing: false,
}
},
methods: {
edit (state) {
this.isEditing = !this.isEditing
}
}
}
</script>
And when I use the component:
<FormComponent>
<input value="Man" type="text" :disabled="!isEditing">
</FormComponent>
The input field are correctly slotted into the component but the :disabled="!isEditing" from the slot isn't reacting to the change of isEditing in the FormComponent.
The Vue documentation is pretty good, but it doesn't cover each edge case.
The component with the <slot></slot> tag has to bind the data onto an attribute on the <slot> tag, like a prop:
<slot :isEditing="isEditing"></slot>
Then when you render that slotted component, Vue creates and exposes an object containing all of the bound data, with each attribute having a property on that object.
Access the object by adding an expression to the v-slot directive in this format:
<FormComponent v-slot:default="slotProps">
(Or use the alias # as in #default="slotProps".) You can access individual properties like isEditing via that object, like slotProps.isEditing:
<FormComponent #default="slotProps">
<input value="Man" type="text" :disabled="!slotProps.isEditing">
</FormComponent>
Here's the more common (and versatile) <template> syntax:
<FormComponent>
<template #default="slotProps">
<input value="Man" type="text" :disabled="!slotProps.isEditing">
</template>
</FormComponent>
You can also destructure slotProps for more direct access to the properties:
<FormComponent>
<template #default="{ isEditing }">
<input value="Man" type="text" :disabled="!isEditing">
</template>
</FormComponent>