Vue Slots Vs Props

# Extension of Vue
V-slot can be used directly on a component, without an argument, to indicate that the component's default slot is a scoped slot, and that props passed to the default slot should be available as the variable declared in its attribute value. Fortunately, Vue provides a “context” parameter (often referred to as ctx) to the underlying render function. This “context” argument is an object with the following properties: props: An object of the provided props; children: An array of the VNode children; slots: A function returning a slots object.
Vue will only render the slots which it finds inside the TabCard component’s template. So when the tabPanelSlotName is ‘tab-panel-lily’ Vue will only render Lily’s panel. When the tabPanelSlotName is ‘tab-panel-snape’, Vue will only render Snape’s panel. At last we have two methods, tabHeadSlotName and switchTab.
# Vue constructor options
# i18n
- Type:
I18nOptions
Component based localization option.
- See also:
VueI18nclass constructor options
# Vue injected methods
# $t
Arguments:
{Path} key: required{Locale} locale: optional{Array Object} values: optional
Return:
TranslateResult
Localize the locale message of key. Localize in preferentially component locale messages than global locale messages. If not specified component locale messages, localize with global locale messages. If you specified locale, localize the locale messages of locale. If you specified key of list / named formatting local messages, you must specify values too. For values more details see Formatting.
If default pluralization does not suit your needs, see pluralization rules in constructor options and custom pluralization.
Tip
Note that you need to guarantee this context equal to component instance in lifecycle methods (e.g. in data options, const $t = this.$t.bind(this)).
# $tc
Arguments:
{Path} key: required{number} choice: optional, default 1{Locale} locale: optional{string Array Object} values: optional
Return:
TranslateResult

Localize the locale message of key with pluralization. Localize in preferentially component locale messages than global locale messages. If not specified component locale messages, localize with global locale messages. If you specified locale, localize the locale messages of locale. If you will specify string value to values, localize the locale messages of value. If you will specify Array or Object value to values, you must specify with values of $t.
Tip
Note that you need to guarantee this context equal to component instance in lifecycle methods (e.g. in data options, const $tc = this.$tc.bind(this)).
# $te
Arguments:
{Path} key: required{Locale} locale: optional
Return:
boolean
Check whether key exists. In Vue instance, If not specified component locale messages, check with global locale messages. If you specified locale, check the locale messages of locale.
Tip
Note that you need to guarantee this context equal to component instance in lifecycle methods (e.g. in data options, const $te = this.$te.bind(this)).
# $d
🆕 7.0+
Arguments:
{number Date} value: required{Path Object} key: optional{Locale Object} locale: optional
Return:
DateTimeFormatResult
Localize the datetime of value with datetime format of key. The datetime format of key need to register to dateTimeFormats option of VueI18n class, and depend on locale option of VueI18n constructor. If you will specify locale argument, it will have priority over locale option of VueI18n constructor.
If the datetime format of key not exist in dateTimeFormats option, fallback to depend on fallbackLocale option of VueI18n constructor.
Tip
Note that you need to guarantee this context equal to component instance in lifecycle methods (e.g. in data options, const $d = this.$d.bind(this)).
# $n
🆕 7.0+
Arguments:
{number} value: required{Path Object} format: optional{Locale} locale: optional
Return:
NumberFormatResult
Localize the number of value with number format of format. The number format of format need to register to numberFormats option of VueI18n class, and depend on locale option of VueI18n constructor. If you will specify locale argument, it will have priority over locale option of VueI18n constructor.
If the number format of format not exist in numberFormats option, fallback to depend on fallbackLocale option of VueI18n constructor.
If the second format argument specified as an object, it should have the following properties:
key {Path}: optional, number formatlocale {Locale}: optional, localecompactDisplay {string}: optional, number format optioncurrency {string}: optional, number format optioncurrencyDisplay {string}: optional, number format optioncurrencySign {string}: optional, number format optionlocaleMatcher {string}: optional, number format optionnotation {string}: optional, number format optionnumberingSystem {string}: optional, number format optionsignDisplay {string}: optional, number format optionstyle {string}: optional, number format optionunit {string}: optional, number format optionunitDisplay {string}: optional, number format optionuseGrouping {string}: optional, number format optionminimumIntegerDigits {string}: optional, number format optionminimumFractionDigits {string}: optional, number format optionmaximumFractionDigits {string}: optional, number format optionminimumSignificantDigits {string}: optional, number format optionmaximumSignificantDigits {string}: optional, number format option
Any specified number format options will have priority over numberFormats of VueI18n constructor.
Tip
Note that you need to guarantee this context equal to component instance in lifecycle methods (e.g. in data options, const $n = this.$n.bind(this)).
# Injected properties
# $i18n
Type:
I18nRead only
Get a VueI18n instance. If you are specify.
If you have specified an i18n option at component options, you will be able to get a VueI18n instance at the component, Otherwise, you will be able get root VueI18n instance.
#VueI18n class
VueI18n class implement I18n interface of flowtype definitions
# Static properties
# version
- Type:
string
vue-i18n version.
# availabilities
🆕 7.0+
- Type:
IntlAvailability
Whether the following internationalization features are available:
{boolean} dateTimeFormat: locale sensitive datetime formatting{boolean} numberFormat: locale sensitive number formatting
The above internationalization features are depends on the browser environments, due to implement with ECMAScript Internationalization API (ECMA-402).
# Constructor options
You can specify the below some options of I18nOptions constructor options of flowtype definitions
# locale
Type:
LocaleDefault:
'en-US'
The locale of localization. If the locale contains a territory and a dialect, this locale contains an implicit fallback.
# fallbackLocale
Type:
FallbackLocaleDefault:
false
The locale of fallback localization. For more complex fallback definitions see fallback.
# messages
Type:
LocaleMessagesDefault:
{}
The locale messages of localization.
# dateTimeFormats
🆕 7.0+
Type:
DateTimeFormatsDefault:
{}
The datetime formats of localization.
- See also:
DateTimeFormatstype of flowtype definitions
# numberFormats
🆕 7.0+
Type:
NumberFormatsDefault:
{}
The number formats of localization.
- See also:
NumberFormatstype of flowtype definitions
# availableLocales
🆕 8.9.0+
Type:
Locale[]Default:
[]Examples:
['en', 'ja']
The list of available locales in messages in lexical order.
# formatter
Type:
FormatterDefault: Built in formatter
The formatter that implemented with Formatter interface.
# modifiers
🆕 8.15.0+
Type:
ModifiersDefault:
loweranduppermodifiers
Modifiers functions for linked messages
# missing
Type:
MissingHandlerDefault:
null
A handler for localization missing. The handler gets called with the localization target locale, localization path key, the Vue instance and values.
If missing handler is assigned, and occurred localization missing, it's not warned.
# fallbackRoot
Type:
BooleanDefault:
true
In the component localization, whether to fall back to root level (global) localization when localization fails.
If false, it's warned, and is returned the key.
# sync
Type:
BooleanDefault:
true
Whether synchronize the root level locale to the component localization locale.
If false, regardless of the root level locale, localize for each component locale.
# silentTranslationWarn
6.1+, 🆙 8.13
Type:
Boolean RegExpDefault:
false
Whether suppress warnings outputted when localization fails.
If true, suppress localization fail warnings.If you use regular expression, you can suppress localization fail warnings that it match with translation key (e.g. $t).
# silentFallbackWarn
🆕 8.8+, 🆙 8.13
- Type:
Boolean RegExp - Default:
false
Whether suppress warnings when falling back to either fallbackLocale or root.
If true, warnings will be generated only when no translation is available at all, and not for fallbacks.If you use regular expression, you can suppress the fallback warnings that it match key (e.g. $t).
# pluralizationRules
8.5+
Type:
PluralizationRulesDefault:
{}
A set of rules for word pluralization in a following format:
# preserveDirectiveContent
8.7+
Type:
BooleanDefault:
false
Whether v-t directive's element should preserve textContent after directive is unbinded.
# warnHtmlInMessage
8.11+
Type:
WarnHtmlInMessageLevelDefault:
off
Whether to allow the use locale messages of HTML formatting. See the warnHtmlInMessage property.
Important!!
In next major version, warnHtmlInMessage option is warn as default.
# sharedMessages
8.12+
Type:
LocaleMessagesDefault:
undefined
The shared locale messages of localization for components. More detail see Component based localization.
# postTranslation
8.16+
Type:
PostTranslationHandlerDefault:
null
A handler for post processing of translation. The handler gets after being called with the $t, t, $tc, and tc.
This handler is useful if you want to filter on translated text such as space trimming.
# componentInstanceCreatedListener
8.18+
Type:
ComponentInstanceCreatedListenerDefault:
null
A handler for getting notified when component-local instance was created. The handler gets called with new and old (root) VueI18n instances.
This handler is useful when extending the root VueI18n instance and wanting to also apply those extensions to component-local instance.
# escapeParameterHtml
8.22+
Type:
BooleanDefault:
false
If escapeParameterHtml is configured as true then interpolation parameters are escaped before the message is translated.This is useful when translation output is used in v-html and the translation resource contains html markup (e.g. <b>around a user provided value). This usage pattern mostly occurs when passing precomputed text strings into UI compontents.
The escape process involves replacing the following symbols with their respective HTML character entities: <, >, ', '.
Setting escapeParameterHtml as true should not break existing functionality but provides a safeguard against a subtletype of XSS attack vectors.
# Properties
# locale
Type:
LocaleRead/Write
The locale of localization. If the locale contains a territory and a dialect, this locale contains an implicit fallback.
# fallbackLocale
Type:
FallbackLocaleRead/Write
The locale of fallback localization. For more complex fallback definitions see fallback.
# messages
Type:
LocaleMessagesRead only
The locale messages of localization.
# dateTimeFormats
🆕 7.0+
Type:
DateTimeFormatsRead only
The datetime formats of localization.
# numberFormats
🆕 7.0+
Type:
NumberFormatsRead only
The number formats of localization.
# missing
Type:
MissingHandlerRead/Write
A handler for localization missing.
# formatter
Type:
FormatterRead/Write
The formatter that implemented with Formatter interface.
# silentTranslationWarn
6.1+, 🆙 8.13
Type:
Boolean RegExpRead/Write
Whether suppress warnings outputted when localization fails.
# silentFallbackWarn
🆕 8.8+, 🆙 8.13
Type:
Boolean RegExpRead/Write
Whether suppress fallback warnings when localization fails.
# pluralizationRules
8.5+
Type:
PluralizationRulesRead/Write
A set of locale-dependent rules for word pluralization.
# preserveDirectiveContent
8.7+
Type:
BooleanRead/Write
Whether v-t directive's element should preserve textContent after directive is unbinded.
# warnHtmlInMessage
8.11+
Type:
WarnHtmlInMessageLevelRead/Write
Whether to allow the use locale messages of HTML formatting.
If you set warn orerror, will check the locale messages on the VueI18n instance.
If you are specified warn, a warning will be output at console.If you are specified error will occurred an Error.
In VueI18n instance, set the off as default.
# postTranslation
8.16+
Type:
PostTranslationHandlerRead/Write
A handler for post processing of translation.
# Methods
# getChoiceIndex
Arguments:
{number} choice{number} choicesLength
Return:
finalChoice {number}
Get pluralization index for current pluralizing number and a given amount of choices.Can be overridden through prototype mutation:
However, for most usages pluralizationRules constructor option should be enough.
# getLocaleMessage( locale )
Arguments:
{Locale} locale
Return:
LocaleMessageObject
Get the locale message of locale.
# setLocaleMessage( locale, message )
Arguments:
{Locale} locale{LocaleMessageObject} message
Set the locale message of locale.
NOTE
8.11+
If you set warn orerror in the warnHtmlInMessage property, when this method is executed, it will check if HTML formatting is used for locale message.
# mergeLocaleMessage( locale, message )
6.1+
Arguments:
{Locale} locale{LocaleMessageObject} message
Vue Slot Event
Merge the registered locale messages with the locale message of locale.
NOTE
8.11+
If you set warn orerror in the warnHtmlInMessage property, when this method is executed, it will check if HTML formatting is used for locale message.
# t( key, [locale], [values] )
Arguments:
{Path} key: required{Locale} locale: optional{Array Object} values: optional
Return: :
TranslateResult
This is the same as the Function returned with $t method. More detail see $t.
# tc( key, [choice], [values] )
Arguments:
{Path} key: required{number} choice: optional, default1{string Array Object} values: optional
Return:
TranslateResult
This is the same as the Function returned $tc method. More detail see $tc.
# te( key, [locale] )
Arguments:
{string} key: required{Locale} locale: optional
Return:
boolean
Check whether key path exists in global locale message. If you specified locale, check the locale message of locale.
# getDateTimeFormat ( locale )
🆕 7.0+
Arguments:
{Locale} locale
Return:
DateTimeFormat
Get the datetime format of locale.
# setDateTimeFormat ( locale, format )
🆕 7.0+
Arguments:
{Locale} locale{DateTimeFormat} format
Set the datetime format of locale.
# mergeDateTimeFormat ( locale, format )
🆕 7.0+
Arguments:
{Locale} locale{DateTimeFormat} format
Merge the registered datetime formats with the datetime format of locale.
# d( value, [key], [locale] )
🆕 7.0+

Arguments:
{number Date} value: required{Path Object} key: optional{Locale Object} locale: optional
Return:
DateTimeFormatResult
This is the same as $d method of Vue instance method. More detail see $d.
# getNumberFormat ( locale )
🆕 7.0+
Arguments:
{Locale} locale
Return:
NumberFormat
Get the number format of locale.
# setNumberFormat ( locale, format )
🆕 7.0+
Arguments:
{Locale} locale{NumberFormat} format
Set the number format of locale.
# mergeNumberFormat ( locale, format )
🆕 7.0+
Arguments:
{Locale} locale{NumberFormat} format
Merge the registered number formats with the number format of locale.
# n( value, [format], [locale] )
🆕 7.0+
Arguments:
{number} value: required{Path Object} format: optional{Locale} locale: optional
Return:
NumberFormatResult
This is the same as $n method of Vue instance method. More detail see $n.
# Directives
🆕 7.3+
# v-t
Expects:
string ObjectModifiers:
.preserve: (8.7.0+) preserves elementtextContentwhen directive is unbinded.
Details:
Update the element textContent that localized with locale messages. You can use string syntax or object syntax. string syntax can be specified as a keypath of locale messages. If you can be used object syntax, you need to specify as the object key the following params:
NOTE
The element textContent will be cleared by default when v-t directive is unbinded. This might be undesirable situation when used inside transitions. To preserve textContent data after directive unbind use .preserve modifier or global preserveDirectiveContent option.
- Examples:
- See also:Custom directive localization
# Components
# i18n functional component
🆕 7.0+
# Props:
path {Path}: required, keypath of locale messageslocale {Locale}: optional, localetag {string boolean Object}: optional, default'span'places {Array Object}: optional (7.2+)
Important!!
In next major version, places prop is deprecated. Please switch to slots syntax.
# Usage:
# See also:
# i18n-n functional component
🆕 8.10+
# Props:
value {number}: required, number to formatformat {string NumberFormatOptions}: optional, number format name or object with explicit format optionslocale {Locale}: optional, localetag {string boolean Object}: optional, default'span'
# Usage:
# Scoped slots
<i18n-n> functional component can accept a number of named scoped slots. List of supported slot names is based on Intl.NumberFormat.formatToParts() output types:
currencydecimalfractiongroupinfinityintegerliteralminusSignnanplusSignpercentSign
Each of these named scoped slots will accept three scope parameters:
[slotName] {FormattedNumberPartType}: parameter of the same name as actual slot name (likeinteger)index {Number}: index of the specific part in the array of number partsparts {Array}: array of all formatted number parts
# See also:
# Special Attributes
# place
🆕 7.2+
# Expects: {number string}
Used on component interpolation to indicate which index of list formatting or key of named formatting.
For detailed usage, see the guide section linked below.
# See also:
Smashing Newsletter
Every week, we send out useful front-end & UX techniques. Subscribe and get the Smart Interface Design Checklists PDF delivered to your inbox.
With the recent release of Vue 2.6, the syntax for using slots has been made more succinct. This change to slots has gotten me re-interested in discovering the potential power of slots to provide reusability, new features, and clearer readability to our Vue-based projects. What are slots truly capable of?
If you’re new to Vue or haven’t seen the changes from version 2.6, read on. Probably the best resource for learning about slots is Vue’s own documentation, but I’ll try to give a rundown here.
What Are Slots?
Slots are a mechanism for Vue components that allows you to compose your components in a way other than the strict parent-child relationship. Slots give you an outlet to place content in new places or make components more generic. The best way to understand them is to see them in action. Let’s start with a simple example:
This component has a wrapper div. Let’s pretend that div is there to create a stylistic frame around its content. This component is able to be used generically to wrap a frame around any content you want. Let’s see what it looks like to use it. The frame component here refers to the component we just made above.
The content that is between the opening and closing frame tags will get inserted into the frame component where the slot is, replacing the slot tags. This is the most basic way of doing it. You can also specify default content to go into a slot simply by filling it in:
So now if we use it like this instead:
The default text of “This is the default content if nothing gets specified to go here” will show up, but if we use it as we did before, the default text will be overridden by the img tag.
Multiple/Named Slots
You can add multiple slots to a component, but if you do, all but one of them is required to have a name. If there is one without a name, it is the default slot. Here’s how you create multiple slots:
We kept the same default slot, but this time we added a slot named header where you can enter a title. You use it like this:
Just like before, if we want to add content to the default slot, just put it directly inside the titled-frame component. To add content to a named slot, though, we needed to wrap the code in a template tag with a v-slot directive. You add a colon (:) after v-slot and then write the name of the slot you want the content to be passed to. Note that v-slot is new to Vue 2.6, so if you’re using an older version, you’ll need to read the docs about the deprecated slot syntax.
Scoped Slots
One more thing you’ll need to know is that slots can pass data/functions down to their children. To demonstrate this, we’ll need a completely different example component with slots, one that’s even more contrived than the previous one: let’s sorta copy the example from the docs by creating a component that supplies the data about the current user to its slots:
This component has a property called user with details about the user. By default, the component shows the user’s last name, but note that it is using v-bind to bind the user data to the slot. With that, we can use this component to provide the user data to its descendant:
To get access to the data passed to the slot, we specify the name of the scope variable with the value of the v-slot directive.
There are a few notes to take here:
- We specified the name of
default, though we don’t need to for the default slot. Instead we could just usev-slot='slotProps'. - You don’t need to use
slotPropsas the name. You can call it whatever you want. - If you’re only using a default slot, you can skip that inner
templatetag and put thev-slotdirective directly onto thecurrent-usertag. - You can use object destructuring to create direct references to the scoped slot data rather than using a single variable name. In other words, you can use
v-slot='{user}'instead ofv-slot='slotProps'and then you can useuserdirectly instead ofslotProps.user.
Taking those notes into account, the above example can be rewritten like this:
A couple more things to keep in mind:
- You can bind more than one value with
v-binddirectives. So in the example, I could have done more than justuser. - You can pass functions to scoped slots too. Many libraries use this to provide reusable functional components as you’ll see later.
v-slothas an alias of#. So instead of writingv-slot:header='data', you can write#header='data'. You can also just specify#headerinstead ofv-slot:headerwhen you’re not using scoped slots. As for default slots, you’ll need to specify the name ofdefaultwhen you use the alias. In other words, you’ll need to write#default='data'instead of#='data'.
There are a few more minor points you can learn about from the docs, but that should be enough to help you understand what we’re talking about in the rest of this article.
What Can You Do With Slots?
Slots weren’t built for a single purpose, or at least if they were, they’ve evolved way beyond that original intention to be a powerhouse tool for doing many different things.
Reusable Patterns
Components were always designed to be able to be reused, but some patterns aren’t practical to enforce with a single “normal” component because the number of props you’ll need in order to customize it can be excessive or you’d need to pass large sections of content and potentially other components through the props. Slots can be used to encompass the “outside” part of the pattern and allow other HTML and/or components to placed inside of them to customize the “inside” part, allowing the component with slots to define the pattern and the components injected into the slots to be unique.
For our first example, let’s start with something simple: a button. Imagine you and your team are using Bootstrap*. With Bootstrap, your buttons are often strapped with the base `btn` class and a class specifying the color, such as `btn-primary`. You can also add a size class, such as `btn-lg`.
* I neither encourage nor discourage you from doing this, I just needed something for my example and it’s pretty well known.
Let’s now assume, for simplicity’s sake that your app/site always uses btn-primary and btn-lg. You don’t want to always have to write all three classes on your buttons, or maybe you don’t trust a rookie to remember to do all three. In that case, you can create a component that automatically has all three of those classes, but how do you allow customization of the content? A prop isn’t practical because a button tag is allowed to have all kinds of HTML in it, so we should use a slot.
Now we can use it everywhere with whatever content you want:
Vue Slot Or Prop
Of course, you can go with something much bigger than a button. Sticking with Bootstrap, let’s look at a modal, or least the HTML part; I won’t be going into functionality… yet.
Now, let’s use this:
The above type of use case for slots is obviously very useful, but it can do even more.
Reusing Functionality
Vue components aren’t all about the HTML and CSS. They’re built with JavaScript, so they’re also about functionality. Slots can be useful for creating functionality once and using it in multiple places. Let’s go back to our modal example and add a function that closes the modal:
Now when you use this component, you can add a button to the footer that can close the modal. Normally, in the case of a Bootstrap modal, you could just add data-dismiss='modal' to a button, but we want to hide Bootstrap specific things away from the components that will be slotting into this modal component. So we pass them a function they can call and they are none the wiser about Bootstrap’s involvement:
Renderless Components
And finally, you can take what you know about using slots to pass around reusable functionality and strip practically all of the HTML and just use the slots. That’s essentially what a renderless component is: a component that provides only functionality without any HTML.
Making components truly renderless can be a little tricky because you’ll need to write render functions rather than using a template in order to remove the need for a root element, but it may not always be necessary. Let’s take a look at a simple example that does let us use a template first, though:
This is an odd example of a renderless component because it doesn’t even have any JavaScript in it. That’s mostly because we’re just creating a pre-configured reusable version of a built-in renderless function: transition.
Yup, Vue has built-in renderless components. This particular example is taken from an article on reusable transitions by Cristi Jora and shows a simple way to create a renderless component that can standardize the transitions used throughout your application. Cristi’s article goes into a lot more depth and shows some more advanced variations of reusable transitions, so I recommend checking it out.
For our other example, we’ll create a component that handles switching what is shown during the different states of a Promise: pending, successfully resolved, and failed. It’s a common pattern and while it doesn’t require a lot of code, it can muddy up a lot of your components if the logic isn’t pulled out for reusability.
So what is going on here? First, note that we are receiving a prop called promise that is a Promise. In the watch section we watch for changes to the promise and when it changes (or immediately on component creation thanks to the immediate property) we clear the state, and call then and catch on the promise, updating the state when it either finishes successfully or fails.
Then, in the template, we show a different slot based on the state. Note that we failed to keep it truly renderless because we needed a root element in order to use a template. We’re passing data and error to the relevant slot scopes as well.
And here’s an example of it being used:
We pass in somePromise to the renderless component. While we’re waiting for it to finish, we’re displaying “Working on it…” thanks to the pending slot. If it succeeds we display “Resolved:” and the resolution value. If it fails we display “Rejected:” and the error that caused the rejection. Now we no longer need to track the state of the promise within this component because that part is pulled out into its own reusable component.
So, what can we do about that span wrapping around the slots in promised.vue? To remove it, we’ll need to remove the template portion and add a render function to our component:
Vue Slot Examples
There isn’t anything too tricky going on here. We’re just using some if blocks to find the state and then returning the correct scoped slot (via this.$scopedSlots['SLOTNAME'](...)) and passing the relevant data to the slot scope. When you’re not using a template, you can skip using the .vue file extension by pulling the JavaScript out of the script tag and just plunking it into a .js file. This should give you a very slight performance bump when compiling those Vue files.
This example is a stripped-down and slightly tweaked version of vue-promised, which I would recommend over using the above example because they cover over some potential pitfalls. There are plenty of other great examples of renderless components out there too. Baleada is an entire library full of renderless components that provide useful functionality like this. There’s also vue-virtual-scroller for controlling the rendering of list item based on what is visible on the screen or PortalVue for “teleporting” content to completely different parts of the DOM.
I’m Out
Vue’s slots take component-based development to a whole new level, and while I’ve demonstrated a lot of great ways slots can be used, there are countless more out there. What great idea can you think of? What ways do you think slots could get an upgrade? If you have any, make sure to bring your ideas to the Vue team. God bless and happy coding.