---
name: component-props
description: Declare and use props with type safety and validation
---
# Component Props
Props are custom attributes for passing data from parent to child components.
## Type-Based Declaration (Recommended)
Use TypeScript interfaces with `defineProps`:
```vue
```
## Reactive Props Destructure (3.5+)
Destructure props while keeping reactivity:
```vue
```
### Passing destructured props to functions
```ts
const { foo } = defineProps(['foo'])
// ❌ Won't work - passes value not reactive source
watch(foo, /* ... */)
// ✅ Wrap in getter
watch(() => foo, /* ... */)
// ✅ For composables
useComposable(() => foo)
```
## Default Values with withDefaults (3.4 and below)
```vue
```
## Runtime Declaration
For runtime validation without TypeScript:
```vue
```
## Prop Types
Supported `type` values:
- `String`, `Number`, `Boolean`, `Array`, `Object`
- `Date`, `Function`, `Symbol`, `Error`
- Custom classes (uses `instanceof`)
```ts
class Person {
constructor(public name: string) {}
}
defineProps({
author: Person // instanceof check
})
```
## Nullable Props
```ts
defineProps({
id: {
type: [String, null],
required: true
}
})
```
## Boolean Casting
Boolean props have special casting rules:
```vue
```
## One-Way Data Flow
Props form a one-way binding: parent → child. Never mutate props directly.
```ts
const props = defineProps(['initialCounter'])
// ❌ Don't mutate props
props.initialCounter = 5
// ✅ Use local state initialized from prop
const counter = ref(props.initialCounter)
// ✅ Or use computed for transformations
const normalizedSize = computed(() => props.size.trim().toLowerCase())
```
## Passing Props
```vue-html
```
## Prop Name Casing
- Declare with camelCase in JavaScript
- Use kebab-case in templates
```ts
defineProps({
greetingMessage: String
})
```
```vue-html
```