useSplitAttrs
Composable interno — utilizzato da tutti i campi form della libreria che dichiarano
inheritAttrs: false.
I campi form dichiarano inheritAttrs: false per evitare che gli attributi finiscano sul
wrapper anziché sul controllo. Senza ribattere $attrs da nessuna parte, però, li
scartavano tutti in silenzio: class, style, data-* e gli attributi ARIA extra
sparivano dal DOM. Questo composable, introdotto nella 1.9.0, li riparte fra i due
elementi.
Firma TypeScript
export function useSplitAttrs(options?: UseSplitAttrsOptions): UseSplitAttrsResult
export interface UseSplitAttrsOptions {
exclude?: string[]; // attributi da non ribattere sul controllo interno
}
export interface UseSplitAttrsResult {
attrs: Record<string, unknown>;
rootAttrs: ComputedRef<Record<string, unknown>>;
controlAttrs: ComputedRef<Record<string, unknown>>;
}
Parametri
| Parametro | Tipo | Descrizione |
|---|---|---|
options.exclude | string[] | Attributi aggiuntivi da tenere fuori dal controllo interno, oltre a quelli sempre esclusi |
Valore di Ritorno
| Proprietà | Tipo | Descrizione |
|---|---|---|
attrs | Record<string, unknown> | $attrs grezzi, per leggere singole chiavi (es. attrs.id) |
rootAttrs | ComputedRef<Record<string, unknown>> | class e style, da applicare al wrapper radice |
controlAttrs | ComputedRef<Record<string, unknown>> | Tutti gli altri attributi, da applicare al controllo interno |
Ripartizione
| Attributo | Destinazione |
|---|---|
class, style | rootAttrs → wrapper radice (si fondono con le classi del componente) |
data-*, name, aria-* extra, listener non dichiarati | controlAttrs → controllo interno |
id, aria-describedby | Esclusi: già calcolati dal componente |
id e aria-describedby sono sempre esclusi perché il componente li costruisce da sé —
il primo per l'associazione con la <label>, il secondo concatenando gli id di helper text,
messaggio di errore e counter. Un pass-through cieco li sovrascriverebbe, perdendo
l'associazione con i messaggi.
Esempio
<script setup lang="ts">
defineOptions({ inheritAttrs: false })
import { useSplitAttrs } from '@/composables/form'
const { attrs, rootAttrs, controlAttrs } = useSplitAttrs()
const inputId = computed(() => (attrs.id as string) || generatedId.value)
</script>
<template>
<div :class="wrapperClasses" v-bind="rootAttrs">
<input v-bind="controlAttrs" :id="inputId" :class="inputClasses" />
</div>
</template>
L'ordine conta: v-bind="controlAttrs" va prima dei binding espliciti del componente,
così in caso di chiavi duplicate vincono questi ultimi.
Campi compositi
Int4RangeInput e IntervalInput non hanno un singolo controllo nativo: controlAttrs
viene applicato al gruppo [role="group"] che raccoglie i campi. Nei test il campo interno
si raggiunge con [data-testid="..."] input.
Componenti che lo usano
InputText, InputNumber, Password, Textarea, Select, TreeSelect, AutoComplete, DatePicker, DateTimePicker, TimePicker, Int4RangeInput, IntervalInput, SignatureInput.