MiHCM
primitives/@mihcm/ui·v0.21.0·stable

TransferList

Dual-pane shuttle: unassigned on the left, assigned on the right, four move buttons in the middle. Per-side filter and multi-select. Web only.

In context

Workspace admins, project access, feature-flag audience cohorts, and email subscription topics.

Workspace admins

2 admins

Move members between Available and Assigned.

Available
Showing 8 of 8
Admins
2 items

Flag audience

3 cohorts included

Which user cohorts receive this feature flag.

All cohorts
Showing 7 of 7
Targeted
3 items

Basic

Available
Showing 10 of 10
Assigned
0 items
  • None assigned
import { useState } from 'react';
import { TransferList } from '@mihcm/ui/TransferList';
 
const DESIGNATIONS = [
  'CEO', 'CTO', 'CFO', 'VP Engineering', 'Senior Engineer',
  'Engineer', 'Designer', 'Researcher', 'Marketing Lead', 'Sales Lead',
];
 
const [assigned, setAssigned] = useState<Record<string, boolean>>({});
 
<TransferList
  items={DESIGNATIONS}
  assigned={assigned}
  onAssignedChange={setAssigned}
/>

Pre-assigned

Available
Showing 8 of 8
Assigned
2 items
const [assigned, setAssigned] = useState<Record<string, boolean>>({
  'Senior Engineer': true,
  Designer: true,
});

Custom labels (canonical MiHCM use case)

Available designations
Showing 10 of 10
Linked to this role
0 items
  • None assigned
<TransferList
  items={DESIGNATIONS}
  assigned={assigned}
  onAssignedChange={setAssigned}
  leftLabel="Available designations"
  rightLabel="Linked to this role"
/>

Reading the assignment back

const assignedItems = Object.keys(assigned).filter((k) => assigned[k]);

Persisting on form submit

async function handleSubmit() {
  const ids = Object.keys(assigned).filter((k) => assigned[k]);
  await fetch('/api/role/designations', {
    method: 'POST',
    body: JSON.stringify({ ids }),
  });
}