Transfer

Transfer component is used to move items between two lists.

Component Features

  • 🔄 Data Transfer: Move items seamlessly between source and target lists.
  • 🔍 Searchable: Built-in filtering to easily find items in large lists.
  • 🖱️ Drag & Drop: Support drag and drop sorting for the selected items.
  • 📝 Form Integration: Works perfectly with BrForm for data validation.
  • 🎨 Customizable: Extensive slots for custom rendering and theming support.

Basic Usage

The most basic usage of BrTransfer. It requires data for the data source and v-model for the keys of the selected items.

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer } from '@breezeui/vue'

const generateData = (count = 15) => {
  return Array.from({ length: count }).map((_, i) => ({
    key: i,
    label: `Item ${i + 1}`,
    desc: `Description for item ${i + 1}`,
    disabled: i % 5 === 0,
  }))
}

const data = ref(generateData())
const value = ref([1, 4])
</script>

<template>
  <BrTransfer
    v-model="value"
    :data="data"
    :titles="['Source List', 'Target List']"
  />
</template>

Search and Drag Drop

Enable searching by setting filterable. Enable drag and drop sorting in the target list by setting draggable.

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer } from '@breezeui/vue'

const generateData = (count = 20) => {
  return Array.from({ length: count }).map((_, i) => ({
    key: i,
    label: `Item ${i + 1}`,
    desc: `Description for item ${i + 1}`,
    disabled: i % 5 === 0,
  }))
}

const data = ref(generateData())
const value = ref([2, 5])
</script>

<template>
  <BrTransfer
    v-model="value"
    :data="data"
    filterable
    draggable
    :titles="['Available', 'Selected (Draggable)']"
    filter-placeholder="Type to search..."
  >
    <template #option="{ item }">
      <div class="flex flex-col">
        <span class="font-medium">{{ item.label }}</span>
        <span class="text-xs text-muted-foreground">{{ item.desc }}</span>
      </div>
    </template>
  </BrTransfer>
</template>

Form Integration

BrTransfer can be seamlessly integrated with BrForm for form validation.

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer, BrForm, BrFormItem, BrButton } from '@breezeui/vue'

const formData = ref({
  roles: []
})

const rolesData = ref([
  { key: 'admin', label: 'Admin (Admin)' },
  { key: 'editor', label: 'Editor (Editor)' },
  { key: 'viewer', label: 'Viewer (Viewer)' },
  { key: 'guest', label: 'Guest (Guest)' },
])

const handleSubmit = (values: any) => {
  alert(JSON.stringify(formData.value))
}

const handleInvalidSubmit = (errors: any) => {
  console.error('Form validation failed:', errors)
}
</script>

<template>
  <BrForm @submit="handleSubmit" @invalid-submit="handleInvalidSubmit">
    <BrFormItem
      name="roles"
      label="Assign Roles"
      required
      :rules="(val: any[]) => {
        if (!val || val.length === 0) return 'Please select at least one role'
        if (val.length < 2) return 'Select at least 2 roles for security'
        return true
      }"
    >
      <BrTransfer
        v-model="formData.roles"
        :data="rolesData"
        :titles="['Roles', 'Assigned']"
        target-order="push"
      />
    </BrFormItem>
    
    <BrButton type="submit" class="mt-4">Submit Form</BrButton>
  </BrForm>
</template>

Theme Customization

Use BrConfigProvider to customize the theme colors and border radius.

<script setup lang="ts">
import { ref } from 'vue'
import { BrTransfer, BrConfigProvider } from '@breezeui/vue'

const generateData = (count = 5) => {
  return Array.from({ length: count }).map((_, i) => ({
    key: i,
    label: `Item ${i + 1}`,
  }))
}

const data = ref(generateData())
const value = ref([2])
</script>

<template>
  <BrConfigProvider
    :theme="{
      primary: '280 84% 67%',
      radius: '1rem',
    }"
  >
    <div class="p-6 border rounded-2xl bg-card shadow-sm">
      <h3 class="mb-4 font-medium text-primary">Custom Primary Color & Radius</h3>
      <BrTransfer
        v-model="value"
        :data="data"
        :titles="['Theme Left', 'Theme Right']"
      />
    </div>
  </BrConfigProvider>
</template>

API

Transfer Props

NameTypeDefaultDescription
modelValue / v-model(string | number)[][]Selected keys
dataTransferDataItem[][]Data source
filterablebooleanfalseWhether the transfer is filterable
filterPlaceholderstring'Search here'Placeholder for the search input
filterMethod(query: string, item: TransferDataItem) => boolean-Custom filter method
titles[string, string]['Source', 'Target']Titles of the left and right panels
buttonTexts[string, string]['', '']Texts for the left and right buttons
draggablebooleanfalseWhether items in the target panel can be dragged to sort
targetOrder'original' | 'push' | 'unshift''original'Order of the items in the target panel
size'sm' | 'md' | 'lg''md'Size of the component
disabledbooleanfalseWhether the component is disabled
emptyTextstring'No data'Text to display when there is no data

TransferDataItem

PropertyTypeDescription
keystring | numberUnique identifier of the item
labelstringDisplay text
disabledbooleanWhether the item is disabled
[key: string]anyAdditional custom properties

Transfer Emits

NameParametersDescription
update:modelValue(value: (string | number)[])Emitted when the selected items change
change(value: (string | number)[], direction: 'left' | 'right', movedKeys: (string | number)[])Emitted when items are moved between lists
search(query: string, direction: 'left' | 'right')Emitted when the search query changes
left-check-change(checkedKeys: (string | number)[], checkedNodes: TransferDataItem[])Emitted when checked items in the left panel change
right-check-change(checkedKeys: (string | number)[], checkedNodes: TransferDataItem[])Emitted when checked items in the right panel change

Transfer Slots

NameDescription
optionCustom render for data items
leftEmptyCustom empty content for the left panel
rightEmptyCustom empty content for the right panel
leftFooterCustom footer for the left panel
rightFooterCustom footer for the right panel