Sitelet https://github.com/nuxt/nuxt/commit/f6d72628d
Skip to content

Commit f6d7262

Browse files
committed
docs: warn about validating server component props
1 parent b76c1a8 commit f6d7262

1 file changed

Lines changed: 24 additions & 0 deletions

File tree

‎docs/2.directory-structure/1.components.md‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,30 @@ Server components (and islands) must have a single root element. (HTML comments
491491
Props are passed to server components via URL query parameters, and are therefore limited by the possible length of a URL, so be careful not to pass enormous amounts of data to server components via props.
492492
::
493493

494+
::note
495+
Server component props come from the request (URL query or body), so treat them as untrusted input. Nuxt rejects the props most likely to leak through unintentionally: a top-level `as` that the island does not declare (an undeclared prop falls through as an attribute onto the island's root), and, with `vue.runtimeCompiler` enabled, a `template` anywhere in the props. Beyond that, avoid feeding props you have not validated into dynamic component resolution (`<component :is>`{lang=vue}, `h()`, `resolveDynamicComponent()`, or a polymorphic `as` / `asChild` prop), since a string can resolve to any registered component or HTML element.
496+
497+
Props a component does not declare fall through as attributes onto its single root element, so an island whose root is a polymorphic component (e.g. from `reka-ui` / `@nuxt/ui`) can receive attributes you did not bind. Set `defineOptions({ inheritAttrs: false })`{lang=ts} on such islands, or declare the props you accept.
498+
499+
To switch components based on caller input, map a discriminator through an allowlist of imported components rather than passing the raw prop:
500+
501+
```vue
502+
<script setup lang="ts">
503+
import type { Component } from 'vue'
504+
import CardA from './CardA.vue'
505+
import CardB from './CardB.vue'
506+
507+
const props = defineProps<{ variant: string }>()
508+
const allowed: Record<string, Component> = { a: CardA, b: CardB }
509+
const component = allowed[props.variant] ?? CardA
510+
</script>
511+
512+
<template>
513+
<component :is="component" />
514+
</template>
515+
```
516+
::
517+
494518
::warning
495519
Be careful when nesting islands within other islands as each island adds some extra overhead.
496520
::

0 commit comments

Comments
 (0)