[go: up one dir, main page]

0% found this document useful (0 votes)
250 views36 pages

Rethinking Reusability in Vue Sample 1.1.0

The document discusses using provide and inject to share state between a Listbox component and its ListboxOption children. It describes how mouseenter on a ListboxOption would update the activeDescendant property on the parent Listbox to focus that option. It notes that while provide and inject are effective, they can also add complexity when used for compound components.

Uploaded by

Erika
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
250 views36 pages

Rethinking Reusability in Vue Sample 1.1.0

The document discusses using provide and inject to share state between a Listbox component and its ListboxOption children. It describes how mouseenter on a ListboxOption would update the activeDescendant property on the parent Listbox to focus that option. It notes that while provide and inject are effective, they can also add complexity when used for compound components.

Uploaded by

Erika
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 36

Listbox provide

inject InjectionKey
useListbox

bind on
active focused

script setup
Chapter summary

Reusability separates good Vue code from great Vue


code, and the Composition API opens up new frontiers
in reusability. Let's explore that concept.

provide inject
provide inject
ref computed watch watchEffect setup
Chapter summary

Reusable components, e.g. renderless and compound


components, are great user-facing APIs...but the
authoring experience is tough.

provide inject

provide inject
enter
<!-- CustomTagsInput.vue -->
<script setup>
import { ref } from 'vue'
import TagsInput from 'path/to/TagsInput'

const tags = ref([])


</script>

<template>
<TagsInput
v-model="tags"
v-slot="{ removeTag, inputBindings }"
>
<span v-for="tag in tags">
<span>{{ tag }}</span>
<button
type="button"
@click="removeTag(tag)"
>
×
</button>
</span>

<!--
Multiple attributes and event listeners get bound to
the input element. They're all contained inside the
inputBindings object, so that you can v-bind
them more easily
-->
<input
placeholder="Add tag..."
v-bind="inputBindings"
/>
</TagsInput>
</template>

v-slot
v-slot

v-slot

enter

role tabindex aria-selected


aria-activedescendant aria-orientation
v-model Listbox

Listbox

ListboxOption v-for
ListboxOption

Listbox ListboxOption
<template>
<Listbox
:options="options"
v-model="myOption"
v-slot="{
bindings,
focused, focus, focusFirst, focusLast,
selected, select
}"
>
<ul v-bind="bindings">
<ListboxOption
v-for="option in options"
:key="option"
:option="option"
v-slot="{
bindings,
isFocused, isSelected,
focusPrevious, focusNext
}"
>
<li v-bind="bindings">
<span>{{ option }}</span>
<CheckIcon v-show="isSelected()" />
</li>
</ListboxOption>
</ul>
</Listbox>
</template>

<script setup>
import { ref } from 'vue'
import { CheckIcon } from '@heroicons/vue/solid'
import { Listbox, ListboxOption } from './Listbox'
import { options } from 'path/to/options'

const myOption = ref(options[0])


</script>
v-model v-
for v-slot

ListboxOption Listbox

option
select

A nicely built renderless or compound component makes


you feel like you're writing HTML with superpowers.
<!-- MyRenderlessComponent.vue -->
<template>
<!--
If you bind data to this slot, it becomes a
scoped slot.
-->
<slot />
</template>

<script setup>
// Normal Vue setup code goes here
</script>

this.$slots this.$scopedSlots
.ts .js

export const Root = {


setup: (props, { slots }) {
...
return () => slots.default({ ... })
}
}

export const Child = {


setup: (props, { slots }) {
...
return () => slots.default({ ... })
}
}

export const AnotherChild = {


setup: (props, { slots }) {
...
return () => slots.default({ ... })
}
}
provide inject

provide inject

Listbox
ListboxOption
Listbox aria-activedescendant

ListboxOption
isFocused true

mouseenter

aria-activedescendant isFocused true


isFocused ListboxOption false

Listbox

ListboxOption

Listbox mouseenter
ListboxOption
Listbox

Listbox option-1
aria-activedescendant
Listbox
ListboxOption

isFocused true

option-1 isFocused() true


false option-2

ListboxOption emit
Listbox

ListboxOption
<template>
<Listbox
:options="options"
v-model="myOption"
v-slot="{
bindings,
focused, focus, focusFirst, focusLast,
selected, select
}"
>
<ul v-bind="bindings">
<ListboxOption
v-for="option in options"
:key="option"
:option="option"
v-slot="{
bindings,
isFocused, isSelected,
focusPrevious, focusNext
}"
>
<li v-bind="bindings">
<span>{{ option }}</span>
<CheckIcon v-show="isSelected()" />
</li>
</ListboxOption>
</ul>
</Listbox>
</template>
activeDescendant
ListboxOptions
ListboxOption mouseenter Listbox

Listbox

provide inject

ListboxOption
provide Listbox inject
ListboxOption emit Listbox
ListboxOption

Listbox

Listbox focus

Listbox provide focus

ListboxOption inject focus


provide inject

provide inject

provide inject

provide inject

provide inject

provide inject

Listbox

provide and inject ! They're effective and


interesting, but relatively obscure, and can get
dizzyingly complex.
.vue
template script style

.vue
.js

.vue

.js

.js

provide
inject
Listbox

Listbox

Usually, writing reusable components is a great


experience! In my opinion, compound components are
the exception to the rule.

You might also like