v-bind not unwrapping reactive properties from composable

I have a helper composable here for orchestrating common aria attributes for form fields.

export function useFieldControl(args: UseFieldControlArgs): UseFieldControlReturn {
  const fieldId = args.id || useId();
  const labelId = `${fieldId}-label`;
  const descriptionId = computed(() => (args.description ? `${fieldId}-description` : undefined));
  const errorId = computed(() => (args.error ? `${fieldId}-error` : undefined));

  const labelProps = computed(() => ({ htmlFor: fieldId, id: labelId }));
  const descriptionProps = computed(() => ({ id: descriptionId.value }));
  const errorProps = computed(() => ({ id: errorId.value }));

  const fieldProps = computed(() => {
    const describedby = [descriptionId.value, errorId.value].filter(
      (id) => typeof id !== "undefined",
    );

    return {
      "aria-describedby": describedby.length ? describedby.join(" ") : undefined,
      "aria-invalid": Boolean(errorId.value) || undefined,
      "aria-labelledby": labelId,
      id: fieldId,
    };
  });

  return { labelProps, descriptionProps, errorProps, fieldProps };
}


i try to use it in a consuming component without destructuring the returned object

// TextField.vue
const args = useFieldControl(props);


and 'spreading' the props for each respective component via v-bind

<template>
  <div class="text-field">
    <VFieldLabel v-bind="args.labelProps">{{ label }}</VFieldLabel>
    ...rest of component
  </div>
</template>


however the v-bind only works if i either add the .value to the end of each object or if i destructure the values in the script and reference them that way. am i doing something wrong? i was under the impression v-bind unwraps computed values automagically....
Was this page helpful?