Form Field

An enterprise-grade form field component based on BrConfigProvider for global theme configuration. It supports multi-control integration, state linkage, and customizable layouts, making it seamless to integrate with inline forms like BrForm and BrTable.

Component Features

  • 🎨 Theme Configuration: Inherits global theme settings (colors, rounded corners, sizes) via BrConfigProvider.
  • 🔄 State Linkage: Automatically links label, border, and message colors based on the field's state (e.g., error, success).
  • 📐 Flexible Layout: Supports positioning labels on the top, left, or right, along with customizable label widths.
  • 🛠️ Customization: Easy to override default styles using TailwindCSS or custom class names.

Basic Usage

Displays a basic form field containing a label, control, and description.

<script setup lang="ts">
import { ref } from 'vue'
import { BrFormField } from '@breeze-ui/vue'

const value = ref('')
</script>

<template>
  <div class="max-w-sm">
    <BrFormField 
      label="Username" 
      description="This is your public display name."
      name="username"
    >
      <template #default="{ id, disabled, readonly, state }">
        <input 
          :id="id" 
          v-model="value" 
          :disabled="disabled"
          :readonly="readonly"
          class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
          :class="{ 'border-[var(--destructive)]': state === 'error' }"
          placeholder="Enter username"
        />
      </template>
    </BrFormField>
  </div>
</template>

Error State

Shows the coordinated color change effect of the label, border, and hint text when validation fails.

<script setup lang="ts">
import { ref } from 'vue'
import { BrFormField } from '@breeze-ui/vue'

const email = ref('invalid-email')
</script>

<template>
  <div class="max-w-sm">
    <BrFormField 
      label="Email Address" 
      required
      error="Please enter a valid email address."
      state="error"
    >
      <template #default="{ id, state }">
        <input 
          :id="id" 
          v-model="email"
          class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 transition-colors"
          :class="state === 'error' ? 'border-[var(--destructive)] focus-visible:ring-[var(--destructive)]' : ''"
        />
      </template>
    </BrFormField>
  </div>
</template>

Custom Layout

Supports displaying the label on the left or right side, and customizing the label width.

<script setup lang="ts">
import { ref } from 'vue'
import { BrFormField } from '@breeze-ui/vue'

const notification = ref(false)
const agreement = ref(false)
</script>

<template>
  <div class="space-y-6 max-w-sm">
    <!-- Label on the left -->
    <BrFormField 
      label="Push Notifications" 
      description="Receive updates via email."
      label-position="left"
      label-width="120px"
    >
      <template #default="{ id }">
        <input :id="id" v-model="notification" type="checkbox" class="w-4 h-4" />
      </template>
    </BrFormField>

    <!-- Label on the right -->
    <BrFormField 
      label="I have read and agree to the terms." 
      label-position="right"
    >
      <template #default="{ id }">
        <input :id="id" v-model="agreement" type="checkbox" class="w-4 h-4" />
      </template>
    </BrFormField>
  </div>
</template>

State Linkage

Demonstrates disabled, readonly, and loading states. The label and description will automatically adjust their styles to match the state.

<script setup lang="ts">
import { ref } from 'vue'
import { BrFormField } from '@breeze-ui/vue'

const value1 = ref('Some value')
const value2 = ref('Cannot edit this')
const value3 = ref('')
</script>

<template>
  <div class="space-y-6 max-w-sm">
    <!-- Disabled State -->
    <BrFormField 
      label="Disabled Field" 
      description="This field and its label are disabled."
      disabled
    >
      <template #default="{ id, disabled }">
        <input 
          :id="id" 
          v-model="value1" 
          :disabled="disabled"
          class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
        />
      </template>
    </BrFormField>

    <!-- Readonly State -->
    <BrFormField 
      label="Readonly Field" 
      description="This field cannot be modified."
      readonly
    >
      <template #default="{ id, readonly }">
        <input 
          :id="id" 
          v-model="value2" 
          :readonly="readonly"
          class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 read-only:bg-muted read-only:cursor-default"
        />
      </template>
    </BrFormField>

    <!-- Loading State -->
    <BrFormField 
      label="Loading Field" 
      description="Verifying availability..."
      loading
    >
      <template #default="{ id }">
        <input 
          :id="id" 
          v-model="value3" 
          placeholder="Checking..."
          class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 pr-10"
        />
      </template>
    </BrFormField>
  </div>
</template>

API Reference

BrFormField

PropTypeDefaultDescription
namestring-Field name, used for validation binding
labelstring-Label text
descriptionstring-Description message
errorstring-Error message. Setting this will automatically enter the error state
state'default' | 'error' | 'success' | 'warning''default'Custom state
disabledbooleanfalseWhether the field is disabled
readonlybooleanfalseWhether the field is readonly
requiredbooleanfalseWhether the field is required (shows an asterisk)
hideRequiredAsteriskbooleanfalseWhether to hide the required asterisk
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl''md'Field size, inherited from ConfigProvider
labelPosition'top' | 'left' | 'right''top'Label position
labelWidthstring | number-Label width (only effective when position is left or right)
loadingbooleanfalseWhether to show a loading placeholder
isolatedbooleanfalseEnable Shadow DOM for style isolation
zIndexnumber-Layer index, automatically assigned by FormFieldManager by default

BrFormFieldLabel / BrFormFieldDescription / BrFormFieldMessage

Common attributes: Supports passing class for style overriding, and automatically injects state from formFieldContext.

FormFieldManager (Utility)

A singleton utility for managing global form field layering.

import { formFieldManager } from '@breeze-ui/vue/form-field'
// Get the next auto-incremented z-index
const zIndex = formFieldManager.nextZIndex()

// Reset the z-index base
formFieldManager.resetZIndex()