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>