Skip to content

Commit b14a634

Browse files
Move non-prop attributes to a separate section (#340)
* feat: exposed non-prop attributes * fix: added attrs to sidebar * feat: added an example for passed listener * feat: added a note on events validation
1 parent c44d36f commit b14a634

File tree

4 files changed

+158
-85
lines changed

4 files changed

+158
-85
lines changed

src/.vuepress/config.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const sidebar = {
2323
children: [
2424
'/guide/component-registration',
2525
'/guide/component-props',
26+
'/guide/component-attrs',
2627
'/guide/component-custom-events',
2728
'/guide/component-slots',
2829
'/guide/component-provide-inject',
@@ -248,8 +249,14 @@ module.exports = {
248249
text: 'Support Vue',
249250
link: '/support-vuejs/',
250251
items: [
251-
{ text: 'One-time Donations', link: '/support-vuejs/#one-time-donations' },
252-
{ text: 'Recurring Pledges', link: '/support-vuejs/#recurring-pledges' },
252+
{
253+
text: 'One-time Donations',
254+
link: '/support-vuejs/#one-time-donations'
255+
},
256+
{
257+
text: 'Recurring Pledges',
258+
link: '/support-vuejs/#recurring-pledges'
259+
},
253260
{ text: 'T-Shirt Shop', link: 'https://vue.threadless.com/' }
254261
]
255262
}

src/guide/component-attrs.md

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Non-Prop Attributes
2+
3+
> This page assumes you've already read the [Components Basics](component-basics.md). Read that first if you are new to components.
4+
5+
A component non-prop attribute is an attribute or event listener that is passed to a component, but does not have a corresponding property defined in [props](component-props) or [emits](component-custom-events.html#defining-custom-events). Common examples of this include `class`, `style`, and `id` attributes.
6+
7+
## Attribute Inheritance
8+
9+
When a component returns a single root node, non-prop attributes will automatically be added to the root node's attributes. For example, in the instance of a date-picker component:
10+
11+
```js
12+
app.component('date-picker', {
13+
template: `
14+
<div class="date-picker">
15+
<input type="datetime" />
16+
</div>
17+
`
18+
})
19+
```
20+
21+
In the event we need to define the status of the date-picker component via a `data-status` property, it will be applied to the root node (i.e., `div.date-picker`).
22+
23+
```html
24+
<!-- Date-picker component with a non-prop attribute -->
25+
<date-picker data-status="activated"></date-picker>
26+
27+
<!-- Rendered date-picker component -->
28+
<div class="date-picker" data-status="activated">
29+
<input type="datetime" />
30+
</div>
31+
```
32+
33+
Same rule applies to the event listeners:
34+
35+
```html
36+
<date-picker @change="submitChange"></date-picker>
37+
```
38+
39+
```js
40+
app.component('date-picker', {
41+
created() {
42+
console.log(this.$attrs) // { onChange: () => {} }
43+
}
44+
})
45+
```
46+
47+
This might be helpful when we have an HTML element with `change` event as a root element of `date-picker`.
48+
49+
```js
50+
app.component('date-picker', {
51+
template: `
52+
<select>
53+
<option value="1">Yesterday</option>
54+
<option value="2">Today</option>
55+
<option value="3">Tomorrow</option>
56+
</select>
57+
`
58+
})
59+
```
60+
61+
In this case, `change` event listener is passed from the parent component to the child and it will be triggered on native `<select>` `change` event. We won't need to emit an event from the `date-picker` explicitly:
62+
63+
```html
64+
<div id="date-picker" class="demo">
65+
<date-picker @change="showChange"></date-picker>
66+
</div>
67+
```
68+
69+
```js
70+
const app = Vue.createApp({
71+
methods: {
72+
showChange(event) {
73+
console.log(event.target.value) // will log a value of the selected option
74+
}
75+
}
76+
})
77+
```
78+
79+
## Disabling Attribute Inheritance
80+
81+
If you do **not** want a component to automatically inherit attributes, you can set `inheritAttrs: false` in the component's options.
82+
83+
The common scenario for disabling an attribute inheritance is when attributes need to be applied to other elements besides the root node.
84+
85+
By setting the `inheritAttrs` option to `false`, this gives you access to the component's `$attrs` property, which includes all attributes not included to component `props` and `emits` properties (e.g., `class`, `style`, `v-on` listeners, etc.).
86+
87+
Using our date-picker component example from the [previous section]('#attribute-inheritance), in the event we need to apply all non-prop attributes to the `input` element rather than the root `div` element, this can be accomplished by using the `v-bind` shortcut.
88+
89+
```js{5}
90+
app.component('date-picker', {
91+
inheritAttrs: false,
92+
template: `
93+
<div class="date-picker">
94+
<input type="datetime" v-bind="$attrs" />
95+
</div>
96+
`
97+
})
98+
```
99+
100+
With this new configuration, our `data-status` attribute will be applied to our `input` element!
101+
102+
```html
103+
<!-- Date-picker component with a non-prop attribute -->
104+
<date-picker data-status="activated"></date-picker>
105+
106+
<!-- Rendered date-picker component -->
107+
<div class="date-picker">
108+
<input type="datetime" data-status="activated" />
109+
</div>
110+
```
111+
112+
## Attribute Inheritance on Multiple Root Nodes
113+
114+
Unlike single root node components, components with multiple root nodes do not have an automatic attribute fallthrough behavior. If `$attrs` are not bound explicitly, a runtime warning will be issued.
115+
116+
```html
117+
<custom-layout id="custom-layout" @click="changeValue"></custom-layout>
118+
```
119+
120+
```js
121+
// This will raise a warning
122+
app.component('custom-layout', {
123+
template: `
124+
<header>...</header>
125+
<main>...</main>
126+
<footer>...</footer>
127+
`
128+
})
129+
130+
// No warnings, $attrs are passed to <main> element
131+
app.component('custom-layout', {
132+
template: `
133+
<header>...</header>
134+
<main v-bind="$attrs">...</main>
135+
<footer>...</footer>
136+
`
137+
})
138+
```

src/guide/component-basics.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,17 @@ Thanks to the `v-on:enlarge-text="postFontSize += 0.1"` listener, the parent wil
243243
</p>
244244
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
245245

246+
We can list emitted events in the component's `emits` option.
247+
248+
```js
249+
app.component('blog-post', {
250+
props: ['title'],
251+
emits: ['enlarge-text']
252+
})
253+
```
254+
255+
This will allow you to check all the events component emits and optionally [validate them](component-custom-events.html#validate-emitted-events)
256+
246257
### Emitting a Value With an Event
247258

248259
It's sometimes useful to emit a specific value with an event. For example, we may want the `<blog-post>` component to be in charge of how much to enlarge the text by. In those cases, we can use `$emit`'s 2nd parameter to provide this value:

src/guide/component-props.md

Lines changed: 0 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -246,89 +246,6 @@ app.component('blog-post', {
246246

247247
to validate that the value of the `author` prop was created with `new Person`.
248248

249-
## Non-Prop Attributes
250-
251-
A non-prop attribute is an attribute that is passed to a component, but does not have a corresponding prop defined. Common examples of this include `class`, `style`, and `id` attributes.
252-
253-
### Attribute Inheritance
254-
255-
When a component returns a single root node, non-prop attributes will automatically be added to the root node's attributes. For example, in the instance of a date-picker component:
256-
257-
```js
258-
app.component('date-picker', {
259-
template: `
260-
<div class="date-picker">
261-
<input type="datetime" />
262-
</div>
263-
`
264-
})
265-
```
266-
267-
In the event we need to define the status of the date-picker component via a `data-status` property, it will be applied to the root node (i.e., `div.date-picker`).
268-
269-
```html
270-
<!-- Date-picker component with a non-prop attribute -->
271-
<date-picker data-status="activated"></date-picker>
272-
273-
<!-- Rendered date-picker component -->
274-
<div class="date-picker" data-status="activated">
275-
<input type="datetime" />
276-
</div>
277-
```
278-
279-
### Disabling Attribute Inheritance
280-
281-
If you do **not** want a component to automatically inherit attributes, you can set `inheritAttrs: false` in the component's options.
282-
283-
There are two common scenarios when attribute inheritance needs to be disabled:
284-
285-
1. When attributes need to be applied to other elements besides the root node
286-
1. When a component has multiple root nodes
287-
288-
By setting the `inheritAttrs` option to `false`, this gives you access to the component's `$attrs` property, which includes all attributes not included to component `props` and `emits` properties (e.g., `class`, `style`, `v-on` listeners, etc.).
289-
290-
#### Single Root Node
291-
292-
Using our date-picker component example from the [previous section]('#attribute-inheritance), in the event we need to apply all non-prop attributes to the `input` element rather than the root `div` element, this can be accomplished by using the `v-bind` shortcut.
293-
294-
```js{5}
295-
app.component('date-picker', {
296-
inheritAttrs: false,
297-
template: `
298-
<div class="date-picker">
299-
<input type="datetime" v-bind="$attrs" />
300-
</div>
301-
`
302-
})
303-
```
304-
305-
With this new configuration, our `data-status` attribute will be applied to our `input` element!
306-
307-
```html
308-
<!-- Date-picker component with a non-prop attribute -->
309-
<date-picker data-status="activated"></date-picker>
310-
311-
<!-- Rendered date-picker component -->
312-
<div class="date-picker">
313-
<input type="datetime" data-status="activated" />
314-
</div>
315-
```
316-
317-
#### Multiple Root Nodes
318-
319-
Unlike single root node components, components with multiple root nodes do not have an automatic attribute fallthrough behavior if `inheritAttrs` and `$attrs` are not defined. A runtime warning will be issued if this is left off
320-
321-
```js{2,5}
322-
app.component('custom-layout', {
323-
inheritAttrs: false,
324-
template: `
325-
<header>...</header>
326-
<main v-bind="$attrs">...</main>
327-
<footer>...</footer>
328-
`
329-
})
330-
```
331-
332249
## Prop Casing (camelCase vs kebab-case)
333250

334251
HTML attribute names are case-insensitive, so browsers will interpret any uppercase characters as lowercase. That means when you're using in-DOM templates, camelCased prop names need to use their kebab-cased (hyphen-delimited) equivalents:

0 commit comments

Comments
 (0)