Skip to content

Commit ca29d3e

Browse files
committed
docs (#82): update attribute fallthrough docs with more explicit definitions
1 parent de54130 commit ca29d3e

File tree

1 file changed

+48
-46
lines changed

1 file changed

+48
-46
lines changed

src/guide/component-props.md

Lines changed: 48 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -240,67 +240,43 @@ to validate that the value of the `author` prop was created with `new Person`.
240240

241241
## Non-Prop Attributes
242242

243-
A non-prop attribute is an attribute that is passed to a component, but does not have a corresponding prop defined.
243+
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.
244244

245-
While explicitly defined props are preferred for passing information to a child component, authors of component libraries can't always foresee the contexts in which their components might be used. That's why components can accept arbitrary attributes.
245+
### Attribute Inheritance
246246

247-
> TODO: revise this after attrs fallthrough RFC is merged
248-
249-
When the component returns a single root node, attributes will be implicitly added to the root node's props. For example, imagine we're using a 3rd-party `bootstrap-date-input` component with a Bootstrap plugin that requires a `data-date-picker` attribute on the `input`. We can add this attribute to our component instance:
247+
When a component returns a single root node, non-prop attributes will automatically be added to the root node's props. For example, in the instance of a date-picker component:
250248

251249
```html
252-
<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>
250+
<template>
251+
<div class="date-picker">
252+
<input type="datetime" />
253+
</div>
254+
</template>
253255
```
254256

255-
And the `data-date-picker="activated"` attribute will automatically be added to the root element of `bootstrap-date-input`.
256-
257-
If the component receives extraneous attrs, but returns multiple root nodes (a [fragment](TODO:fragment.md)), an automatic merge cannot be performed. In this case you need to select an element to apply the passed attributes via `v-bind="$attrs"`:
257+
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`).
258258

259259
```html
260-
<!-- child component -->
261-
262-
<span>Select a date:</span>
263-
<input v-bind="$attrs" type="date" class="form-control" />
264-
```
265-
266-
`$attrs` instance property contains the attribute names and values passed to a component, such as:
267-
268-
```js
269-
{
270-
required: true,
271-
placeholder: 'Enter your username'
272-
}
260+
<date-picker data-status="activated"></date-picker>
273261
```
274262

275-
If you did not apply `this.$attrs` in a multi-root component explicitly, a runtime warning will be emitted. You can suppress this warning with [Disabling Attribute Inheritance](#disabling-attribute-inheritance).
276-
277-
### Replacing/Merging with Existing Attributes
278-
279-
Imagine this is the template for `bootstrap-date-input`:
280-
281263
```html
282-
<input type="date" class="form-control" />
264+
<!-- Rendered DatePicker Component -->
265+
<template>
266+
<div class="date-picker" data-status="activated">
267+
<input type="datetime" />
268+
</div>
269+
</template>
283270
```
284271

285-
To specify a theme for our date picker plugin, we might need to add a specific class, like this:
286-
287-
```html
288-
<bootstrap-date-input
289-
data-date-picker="activated"
290-
class="date-picker-theme-dark"
291-
></bootstrap-date-input>
292-
```
272+
### Disabling Attribute Inheritance
293273

294-
In this case, two different values for `class` are defined:
274+
There are two common scenarios when attribute inheritance needs to be disabled:
295275

296-
- `form-control`, which is set by the component in its template
297-
- `date-picker-theme-dark`, which is passed to the component by its parent
276+
1. When attributes need to be applied to other elements besides the root node
277+
1. When a component has multiple root nodes (i.e., a [fragment](TODO:fragment.md))
298278

299-
For most attributes, the value provided to the component will replace the value set by the component. So for example, passing `type="text"` will replace `type="date"` and probably break it! Fortunately, the `class` and `style` attributes are a little smarter, so both values are merged, making the final value: `form-control date-picker-theme-dark`.
300-
301-
### Disabling Attribute Inheritance
302-
303-
If you do **not** want the single root element of a component to inherit attributes, you can set `inheritAttrs: false` in the component's options. For example:
279+
To disable automatic attribute inheritance, you can set `inheritAttrs: false` in the component's options. For example:
304280

305281
```js
306282
const app = Vue.createApp({})
@@ -311,7 +287,7 @@ app.component('my-component', {
311287
})
312288
```
313289

314-
With `inheritAttrs: false` and `$attrs`, you can manually decide which element you want to forward attributes to, which is often desirable for [base components](../style-guide/#base-component-names-strongly-recommended):
290+
When you disable `inheritAttrs`, this gives you to access the `$attrs` property, which includes all non-prop attributes (e.g., `class`, `style`, `v-on` listeners, etc.). With `inheritAttrs: false` and `$attrs`, you can explicitly determine which element you want to forward attributes to, which is often desirable for [base components](../style-guide/#base-component-names-strongly-recommended):
315291

316292
```js
317293
app.component('base-input', {
@@ -340,6 +316,32 @@ This pattern allows you to use base components more like raw HTML elements, with
340316
></base-input>
341317
```
342318

319+
If you did not apply `this.$attrs` in a multi-root component explicitly, a runtime warning will be emitted. You can suppress this warning with [Disabling Attribute Inheritance](#disabling-attribute-inheritance).
320+
321+
### Replacing/Merging with Existing Attributes
322+
323+
Imagine this is the template for `bootstrap-date-input`:
324+
325+
```html
326+
<input type="date" class="form-control" />
327+
```
328+
329+
To specify a theme for our date picker plugin, we might need to add a specific class, like this:
330+
331+
```html
332+
<bootstrap-date-input
333+
data-date-picker="activated"
334+
class="date-picker-theme-dark"
335+
></bootstrap-date-input>
336+
```
337+
338+
In this case, two different values for `class` are defined:
339+
340+
- `form-control`, which is set by the component in its template
341+
- `date-picker-theme-dark`, which is passed to the component by its parent
342+
343+
For most attributes, the value provided to the component will replace the value set by the component. So for example, passing `type="text"` will replace `type="date"` and probably break it! Fortunately, the `class` and `style` attributes are a little smarter, so both values are merged, making the final value: `form-control date-picker-theme-dark`.
344+
343345
## Prop Casing (camelCase vs kebab-case)
344346

345347
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)