Skip to content
Snippets Groups Projects
FormGroup.vue 1.39 KiB
Newer Older
<template>
  <div class="form-group tw-block" :class="formGroupClass">
    <label :for="id" class="tw-text-gray-500 tw-font-medium tw-pt-1">{{ label }}</label>
    <div class="tw-flex tw-flex-col">
      <slot v-bind="controlAttributes" />
      <div v-if="hasErrors" :id="errorsId" class="invalid-feedback tw-order-first">
        <template v-for="(error, index) in errorList" :key="index">
          <p class="last:tw-mb-0">{{ t(`error.${error.code}`) }}</p>
        </template>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { computed, inject } from 'vue'
import { useId } from '@/util'
import { useI18n } from '@/i18n'

type Error = {
  code: string
}

const props = defineProps<{
  label: string
  customControl?: boolean
  errors?: undefined | Error[]
}>()

const { t } = useI18n()
const formGroupClass = inject('formGroupClass', undefined)
const id = useId('form-group-control')
const errorsId = useId('form-group-errors')
const errorList = computed<Error[]>(() => props.errors ?? [])
const hasErrors = computed(() => errorList.value.length > 0)
const controlAttributes = computed(() => ({
  class: [
    'tw-order-first',
    { 'is-invalid': hasErrors.value, 'form-control': !props.customControl },
  ],
  'aria-describedby': hasErrors.value ? errorsId.value : '',
  id: id.value,
}))
</script>

<script lang="ts">
export default {
  compatConfig: {
    MODE: 3,
  },
}
</script>