This page assumes you've already read the Components Basics. Read that first if you are
new to components.
Slot Content and☀️ Outlet
We have learned that components can accept
props, which can be JavaScript values of any type. But how about☀️ template content? In
some cases, we may want to pass a template fragment to a child component, and let the
☀️ child component render the fragment within its own template.
For example, we may have a
component that supports usage like☀️ this:
template < FancyButton > Click
me! FancyButton >
The template of looks like
this:
template <☀️ button class = "fancy-btn" > < slot > slot >
button >
The element is☀️ a slot outlet that indicates where the parent-provided
slot content should be rendered.
And the final rendered DOM:
html < button class☀️ =
"fancy-btn" >Click me! button >
With slots, the is responsible for
rendering the outer (and its fancy styling),☀️ while the inner content is
provided by the parent component.
Another way to understand slots is by comparing them
to JavaScript☀️ functions:
js // parent component passing slot content FancyButton (
'Click me!' ) // FancyButton renders slot content in its own☀️ template function
FancyButton ( slotContent ) { return `R${ slotContent }
` }
Slot content is not just limited to☀️ text. It can be any valid template
content. For example, we can pass in multiple elements, or even other
components:
template☀️ < FancyButton > < span style = "color:red" >Click me! span > <
AwesomeIcon name = "plus" /> FancyButton☀️ >
By using slots, our is more
flexible and reusable. We can now use it in different places with different☀️ inner
content, but all with the same fancy styling.
Vue components' slot mechanism is
inspired by the native Web Component ☀️ element, but with additional capabilities
that we will see later.
Render Scope
Slot content has access to the data scope of☀️ the
parent component, because it is defined in the parent. For example:
template < span >{{
message }} span > <☀️ FancyButton >{{ message }} FancyButton >
Here both {{ message
}} interpolations will render the same content.
Slot content does not have☀️ access to
the child component's data. Expressions in Vue templates can only access the scope it
is defined in, consistent☀️ with JavaScript's lexical scoping. In other
words:
Expressions in the parent template only have access to the parent scope;
expressions in☀️ the child template only have access to the child scope.
Fallback Content
There are cases when it's useful to specify fallback☀️ (i.e. default) content for a
slot, to be rendered only when no content is provided. For example, in a
☀️ component:
template < button type = "submit" > < slot > slot > button >
We might
want the text "Submit"☀️ to be rendered inside the if the parent didn't provide
any slot content. To make "Submit" the fallback content,☀️ we can place it in between the
tags:
template < button type = "submit" > < slot > Submit slot > button >
Now when we use in a parent component,
providing no content☀️ for the slot:
template < SubmitButton />
This will render the
fallback content, "Submit":
html < button type = "submit" >Submit button >
But☀️ if we
provide content:
template < SubmitButton >Save SubmitButton >
Then the provided
content will be rendered instead:
html < button type =☀️ "submit" >Save button >
Named
Slots
There are times when it's useful to have multiple slot outlets in a single
component.☀️ For example, in a component with the following
template:
template < div class = "container" > < header > header > < main > ☀️ main > < footer >
footer > div >
For these cases,☀️ the
element has a special attribute, name , which can be used to assign a unique ID to
different☀️ slots so you can determine where content should be rendered:
template < div
class = "container" > < header > <☀️ slot name = "header" > slot > header > < main >
< slot > slot > main☀️ > < footer > < slot name = "footer" > slot > footer >
div >
A outlet☀️ without name implicitly has the name "default".
In a parent
component using , we need a way to pass multiple☀️ slot content fragments,
each targeting a different slot outlet. This is where named slots come in.
To pass a
named slot,☀️ we need to use a element with the v-slot directive, and then
pass the name of the slot as☀️ an argument to v-slot :
template < BaseLayout > < template
v-slot:header > ☀️ template > BaseLayout
>
v-slot has a dedicated shorthand # , so can be shortened to
just . Think of it as "render this template fragment in the child
component's 'header' slot".
Here's the code passing content☀️ for all three slots to
using the shorthand syntax:
template < BaseLayout > < template # header >
< h1☀️ >Here might be a page title h1 > template > < template # default > < p >A
paragraph☀️ for the main content. p > < p >And another one. p > template > <
template # footer☀️ > < p >Here's some contact info p > template > BaseLayout
>
When a component accepts both a☀️ default slot and named slots, all top-level non-
nodes are implicitly treated as content for the default slot. So☀️ the above
can also be written as:
template < BaseLayout > < template # header > < h1 >Here might
be☀️ a page title h1 > template > < p >A paragraph
for the main☀️ content. p > < p >And another one. p > < template # footer > < p
>Here's some contact☀️ info p > template > BaseLayout >
Now everything inside the
elements will be passed to the corresponding☀️ slots. The final rendered HTML
will be:
html < div class = "container" > < header > < h1 >Here might☀️ be a page title
h1 > header > < main > < p >A paragraph for the main content.☀️ p > < p >And another
one. p > main > < footer > < p >Here's some contact☀️ info p > footer > div
>
Again, it may help you understand named slots better using the JavaScript☀️ function
analogy:
js // passing multiple slot fragments with different names BaseLayout ({
header: `...` , default: `...` , footer: `...`☀️ }) // renders them in
different places function BaseLayout ( slots ) { return `
${ slots . default }
. footer }
` }
Dynamic Slot Names
Dynamic directive arguments also
☀️ work on v-slot , allowing the definition of dynamic slot names:
template < base-layout
> < template v-slot: [ dynamicSlotName ]>☀️ ... template > <
template #[ dynamicSlotName ]> ... template > base-layout >
Do☀️ note the
expression is subject to the syntax constraints of dynamic directive arguments.
Scoped
Slots
As discussed in Render Scope, slot☀️ content does not have access to state in the
child component.
However, there are cases where it could be useful if☀️ a slot's content
can make use of data from both the parent scope and the child scope. To achieve that,
☀️ we need a way for the child to pass data to a slot when rendering it.
In fact, we can
do☀️ exactly that - we can pass attributes to a slot outlet just like passing props to a
component:
template < div > < slot : text = "
greetingMessage " : count = " 1 " >☀️ slot > div >
Receiving the slot props is a bit
different when using a single default slot vs. using☀️ named slots. We are going to show
how to receive props using a single default slot first, by using v-slot☀️ directly on the
child component tag:
template < MyComponent v-slot = " slotProps " > {{ slotProps.text
}} {{ slotProps.count }}☀️ MyComponent >
The props passed to the slot by the child are
available as the value of the corresponding v-slot☀️ directive, which can be accessed by
expressions inside the slot.
You can think of a scoped slot as a function being☀️ passed
into the child component. The child component then calls it, passing props as
arguments:
js MyComponent ({ // passing the☀️ default slot, but as a function default : (
slotProps ) => { return `${ slotProps . text }R${ slotProps☀️ . count }` } }) function
MyComponent ( slots ) { const greetingMessage = 'hello' return `
${ // call the
☀️ slot function with props! slots . default ({ text: greetingMessage , count: 1 })
}
` }
In fact, this is very☀️ close to how scoped slots are compiled, and how you
would use scoped slots in manual render functions.
Notice how v-slot="slotProps"
☀️ matches the slot function signature. Just like with function arguments, we can use
destructuring in v-slot :
template < MyComponent v-slot☀️ = " { text, count } " > {{ text
}} {{ count }} MyComponent >
Named Scoped Slots
Named☀️ scoped slots work similarly
- slot props are accessible as the value of the v-slot directive:
v-slot:name="slotProps" . When using☀️ the shorthand, it looks like this:
template <
MyComponent > < template # header = " headerProps " > {{ headerProps☀️ }} template > <
template # default = " defaultProps " > {{ defaultProps }} template > <☀️ template #
footer = " footerProps " > {{ footerProps }} template > MyComponent >
Passing
props to a☀️ named slot:
template < slot name = "header" message = "hello" > slot
>
Note the name of a slot won't be☀️ included in the props because it is reserved - so
the resulting headerProps would be { message: 'hello' } .
If☀️ you are mixing named slots
with the default scoped slot, you need to use an explicit tag for the
☀️ default slot. Attempting to place the v-slot directive directly on the component will
result in a compilation error. This is☀️ to avoid any ambiguity about the scope of the
props of the default slot. For example:
template <
template > < MyComponent v-slot = " { message } " > < p >{{ message }}☀️ p > < template
# footer > ☀️ < p
>{{ message }} p > template > MyComponent > template >
Using an explicit
tag☀️ for the default slot helps to make it clear that the message prop is not
available inside the other slot:
template☀️ < template > < MyComponent > < template # default = " { message☀️ } " > < p >{{ message }}
p > template > < template # footer > < p☀️ >Here's some contact info p > template
> MyComponent > template >
Fancy List Example
You may be☀️ wondering what would
be a good use case for scoped slots. Here's an example: imagine a component
that renders☀️ a list of items - it may encapsulate the logic for loading remote data,
using the data to display a☀️ list, or even advanced features like pagination or infinite
scrolling. However, we want it to be flexible with how each☀️ item looks and leave the
styling of each item to the parent component consuming it. So the desired usage may
☀️ look like this:
template < FancyList : api-url = " url " : per-page = " 10 " > <
template☀️ # item = " { body, username, likes } " > < div class = "item" > < p >{{☀️ body
}} p > < p >by {{ username }} | {{ likes }} likes p > div >☀️ template >
FancyList >
Inside , we can render the same multiple times with
different item data☀️ (notice we are using v-bind to pass an object as slot
props):
template < ul > < li v-for = "☀️ item in items " > < slot name = "item" v-bind =
" item " > slot > li☀️ > ul >
Renderless Components
The use case we
discussed above encapsulates both reusable logic (data fetching, pagination etc.)☀️ and
visual output, while delegating part of the visual output to the consumer component via
scoped slots.
If we push this☀️ concept a bit further, we can come up with components
that only encapsulate logic and do not render anything by☀️ themselves - visual output is
fully delegated to the consumer component with scoped slots. We call this type of
component☀️ a Renderless Component.
An example renderless component could be one that
encapsulates the logic of tracking the current mouse position:
template <☀️ MouseTracker
v-slot = " { x, y } " > Mouse is at: {{ x }}, {{ y }} ☀️ MouseTracker >
While an
interesting pattern, most of what can be achieved with Renderless Components can be
achieved in a more☀️ efficient fashion with Composition API, without incurring the
overhead of extra component nesting. Later, we will see how we can☀️ implement the same
mouse tracking functionality as a Composable.
tcomewhichmays dentitle him Or her to rewin A prize, in The doarder In WhyCH it will
ccur...
online casinos: Mega Joker (99%)👄 Codex of Fortune 98%) Starmania (97.87%) White
Rabbit Microways(1997,72%) Medusa megazona a que96/63%) Secret S Of Atlantis “95”.077%”
Steam Towerm98;04%) Gorilla Go👄 Wilder 1997). 01%) Highest RTPSlotis 2024 - Which US