Framework support reference
A scan reads React and Vue. This page lists, for each, which files are read, how a component is recognised, what else is recorded, and what is not found. Web components such as <acme-button> are counted in both. A file is only read when your config's include patterns match it; see Config reference.
HTML files and Lit templates are not read.
At a glance
| React | Vue | |
|---|---|---|
| Files | .tsx, .jsx, .ts, .js | .vue |
| What is read | JSX anywhere in the file | The <template> and <script> blocks |
| Components found | Imported or locally defined components used as JSX tags, and web components | Imported components, Nuxt auto-imported components, and web components |
| Prop values | Yes | Yes |
| Events | Props named on plus a capital letter, such as onClick | @name and v-on:name |
| Renders and rendered by | Yes | Yes |
Files with any other extension, such as .mjs, .mts, .html or .svelte, are skipped even when include matches them.
Renders and rendered by is what the dashboard's Composition tab shows and what composition holds in the artifact: which components a component's own code renders, and which components render it. Composition explains it.
React
Recognised: a JSX tag with a capital letter or a dot, such as <Button> or <Card.Header>, that names an imported component or one defined in the repo. Components reached through lazy(), through wrappers such as memo() and forwardRef(), or through an object of components are found too, and so are components passed to a function, such as makeControl(Input). In the JSON, each use's trace records how it was reached. A lowercase tag such as <div> is ignored unless it is a web component.
Renders and rendered by: each use counts for the component whose code contains it, so a ProductCard that renders a Button shows up on both. A file that defines several components records each one separately.
Known gaps:
- A tag that renders a component received as a prop, a function parameter or the result of a hook from a package is not counted. The scan reports
late-bound-render.
Vue
Recognised: each .vue file is itself a component, named by the name in defineOptions() or export default, or else by its file name (line-item.vue is LineItem). In its template:
- A tag that matches a script import, written either way (
<LineItem>or<line-item>), is that component. - In a Nuxt app, a tag that matches an auto-imported component is that component. Run
nuxt preparebefore scanning so the list of auto-imports exists. - Any other tag with a hyphen, such as
<acme-button>, is counted as a web component. - Vue's built-in tags, such as
<Transition>and<component>, are ignored, and so are plain HTML tags such as<div>.
Renders and rendered by: every tag in a file's template counts for that file's component, however deeply it is nested.
Known gaps:
- Components registered globally without Nuxt, for example with
app.component(), are not matched to their definition. Written with a capital letter (<PromoBanner>), the tag is an unresolved occurrence. Written with a hyphen (<promo-banner>), it is counted as a web component with no package, which the dashboard's Framework filter shows as Tag. Import the component in the file's script to have it matched. - In a file with both
<script>and<script setup>, a component imported in the plain<script>is not matched. Written<LineItem>, its tag is not counted at all. Written<line-item>, it is counted as a web component with no package. Move the import into<script setup>.
Web components
Recognised: a tag with a hyphen in its name, such as <acme-button>, in React JSX or a Vue template. It is counted even though nothing imports it. Capitals don't matter: <Acme-Button> is the same acme-button. The few SVG and MathML elements with a hyphen, such as <font-face>, are not counted.
Linked to a package or your repo: each tag belongs to one of these, in this order:
- Your repo, when one of its files registers the tag with
customElements.define("…", …)or@customElement("…"). When the registered class is imported from a package, the tag belongs to that package instead. - The package whose Custom Elements Manifest declares the tag. The package must be installed, and its
package.jsonmust point at the manifest with acustomElementsfield. See Link web components to your package. - No package, when neither applies. The tag is still counted, and the dashboard's Framework filter shows it as Tag.
Renders and rendered by: a web component counts for the React or Vue component whose code contains it. Its own Renders list is always empty, because what a web component draws inside itself isn't read.
Known gaps:
- A package that registers its own tags when you import it, such as
import "@acme/elements", isn't linked to them: the scan only looks for registrations in the files it scans. Give the package a manifest. - A manifest that no
customElementsfield points at is not read, including acustom-elements.jsonat your repo's root.
In both frameworks
- A component from a package is found only when the package is installed. Without it, each use of the package is an unresolved occurrence: the JSON keeps it with its reason, and the dashboard leaves it out.
- A capitalised tag that nothing imports or defines, such as
<Widget />, is an unresolved occurrence too.