Droppable Types
Complete type definitions for droppable components and hooks.
Interfaces
UseDroppableOptions<TData>
Configuration options for the useDroppable hook.
interface UseDroppableOptions<TData = unknown> {
onDrop: (data: TData) => void;
dropDisabled?: boolean;
onActiveChange?: (isActive: boolean) => void;
dropAlignment?: DropAlignment;
dropOffset?: DropOffset;
activeStyle?: StyleProp<ViewStyle>;
droppableId?: string;
capacity?: number;
}
Properties
onDrop
- Type:
(data: TData) => void
- Required: Yes
- Description: Callback function fired when an item is successfully dropped on this droppable. This is where you handle the drop logic for your application.
const handleDrop = (data: TaskData) => {
console.log('Task dropped:', data.name);
moveTaskToColumn(data.id, 'completed');
showNotification(`${data.name} completed!`);
};
dropDisabled
- Type:
boolean
- Default:
false
- Description: Whether this droppable is disabled. When true, items cannot be dropped here. Useful for conditionally enabling/disabling drop functionality.
const isDisabled = user.role !== 'admin';
const { viewProps } = useDroppable({
onDrop: handleDrop,
dropDisabled: isDisabled
});
onActiveChange
- Type:
(isActive: boolean) => void
- Required: No
- Description: Callback fired when the active state of this droppable changes. Active state indicates whether a draggable item is currently hovering over this droppable.
const handleActiveChange = (isActive: boolean) => {
if (isActive) {
playHoverSound();
setHighlighted(true);
} else {
setHighlighted(false);
}
};
dropAlignment
- Type:
DropAlignment
- Default:
"center"
- Description: How dropped items should be aligned within this droppable area.
Available alignments:
center
: Center the item within the droppable (default)top-left
: Align to top-left cornertop-center
: Align to top edge, centered horizontallytop-right
: Align to top-right cornercenter-left
: Align to left edge, centered verticallycenter-right
: Align to right edge, centered verticallybottom-left
: Align to bottom-left cornerbottom-center
: Align to bottom edge, centered horizontallybottom-right
: Align to bottom-right corner
// Items dropped here will snap to the top-left corner
const { viewProps } = useDroppable({
onDrop: handleDrop,
dropAlignment: 'top-left'
});
dropOffset
- Type:
DropOffset
- Required: No
- Description: Additional pixel offset to apply after alignment. Useful for fine-tuning the exact position where items are dropped.
// Drop items 10px to the right and 5px down from the center
const { viewProps } = useDroppable({
onDrop: handleDrop,
dropAlignment: 'center',
dropOffset: { x: 10, y: 5 }
});
activeStyle
- Type:
StyleProp<ViewStyle>
- Required: No
- Description: Style to apply when a draggable item is hovering over this droppable. This provides visual feedback to users about valid drop targets.
const activeStyle = {
backgroundColor: 'rgba(0, 255, 0, 0.2)',
borderColor: '#00ff00',
borderWidth: 2,
transform: [{ scale: 1.05 }]
};
const { viewProps } = useDroppable({
onDrop: handleDrop,
activeStyle
});
droppableId
- Type:
string
- Required: No
- Description: Unique identifier for this droppable. If not provided, one will be generated automatically. Used for tracking which droppable items are dropped on.
const { viewProps } = useDroppable({
droppableId: 'todo-column',
onDrop: handleDrop
});
capacity
- Type:
number
- Default:
1
- Description: Maximum number of items that can be dropped on this droppable. When capacity is reached, additional items cannot be dropped here.
// Allow up to 5 items in this drop zone
const { viewProps } = useDroppable({
onDrop: handleDrop,
capacity: 5
});
// Unlimited capacity
const { viewProps } = useDroppable({
onDrop: handleDrop,
capacity: Infinity
});
UseDroppableReturn
Return value from the useDroppable hook.
interface UseDroppableReturn {
viewProps: {
onLayout: (event: LayoutChangeEvent) => void;
style?: StyleProp<ViewStyle>;
};
isActive: boolean;
activeStyle?: StyleProp<ViewStyle>;
animatedViewRef: ReturnType<typeof useAnimatedRef<Animated.View>>;
}
Properties
viewProps
- Type:
{ onLayout: (event: LayoutChangeEvent) => void; style?: StyleProp<ViewStyle>; }
- Description: Props to spread on the view that will act as a drop zone. Contains layout handler and conditional active styling.
isActive
- Type:
boolean
- Description: Whether a draggable item is currently hovering over this droppable. Useful for conditional rendering or additional visual feedback.
activeStyle
- Type:
StyleProp<ViewStyle>
- Description: The active style that was passed in options. Useful for external styling logic.
animatedViewRef
- Type:
ReturnType<typeof useAnimatedRef<Animated.View>>
- Description: Animated ref for the droppable view. Used internally for measurements.
DroppableProps<TData>
Props for the Droppable component.
interface DroppableProps<TData = unknown> extends UseDroppableOptions<TData> {
style?: StyleProp<ViewStyle>;
children: React.ReactNode;
}
Properties
style
- Type:
StyleProp<ViewStyle>
- Required: No
- Description: Style to apply to the droppable container.
children
- Type:
React.ReactNode
- Required: Yes
- Description: The content to render inside the droppable.
Type Aliases
DropAlignment
Alignment options for positioning dropped items within a droppable area.
type DropAlignment =
| 'center'
| 'top-left' | 'top-center' | 'top-right'
| 'center-left' | 'center-right'
| 'bottom-left' | 'bottom-center' | 'bottom-right';
Values
center
: Center the item within the droppable (default)top-left
: Align to top-left cornertop-center
: Align to top edge, centered horizontallytop-right
: Align to top-right cornercenter-left
: Align to left edge, centered verticallycenter-right
: Align to right edge, centered verticallybottom-left
: Align to bottom-left cornerbottom-center
: Align to bottom edge, centered horizontallybottom-right
: Align to bottom-right corner
DropOffset
Pixel offset configuration for fine-tuning drop positioning.
interface DropOffset {
x: number;
y: number;
}
Properties
x
: Horizontal offset in pixels (positive = right, negative = left)y
: Vertical offset in pixels (positive = down, negative = up)
Usage Examples
Basic Droppable
import { useDroppable } from 'react-native-reanimated-dnd';
interface TaskData {
id: string;
title: string;
status: 'todo' | 'in-progress' | 'done';
}
function DropZone({ status }: { status: string }) {
const { viewProps, isActive } = useDroppable({
onDrop: (data: TaskData) => {
console.log(`Task ${data.title} dropped in ${status}`);
updateTaskStatus(data.id, status);
},
droppableId: `${status}-column`
});
return (
<View {...viewProps} style={[styles.dropZone, isActive && styles.active]}>
<Text>{status.toUpperCase()}</Text>
{isActive && <Text>Drop here!</Text>}
</View>
);
}
Droppable with Visual Feedback
function VisualDropZone() {
const activeStyle = {
backgroundColor: 'rgba(34, 197, 94, 0.2)',
borderColor: '#22c55e',
borderWidth: 2,
borderStyle: 'dashed' as const,
transform: [{ scale: 1.02 }]
};
const { viewProps, isActive } = useDroppable({
onDrop: (data) => handleDrop(data),
activeStyle,
onActiveChange: (active) => {
if (active) {
hapticFeedback();
playSound('hover');
}
}
});
return (
<Animated.View {...viewProps} style={styles.dropZone}>
<Icon
name={isActive ? "check-circle" : "plus-circle"}
size={24}
color={isActive ? "#22c55e" : "#6b7280"}
/>
<Text style={[styles.text, isActive && styles.activeText]}>
{isActive ? "Release to drop" : "Drop items here"}
</Text>
</Animated.View>
);
}
Capacity-Limited Droppable
function LimitedDropZone({ maxItems = 3 }: { maxItems?: number }) {
const [droppedItems, setDroppedItems] = useState<TaskData[]>([]);
const isFull = droppedItems.length >= maxItems;
const { viewProps, isActive } = useDroppable({
onDrop: (data: TaskData) => {
if (!isFull) {
setDroppedItems(prev => [...prev, data]);
showToast(`${data.title} added`);
} else {
showError('Drop zone is full!');
}
},
capacity: maxItems,
dropDisabled: isFull,
activeStyle: {
backgroundColor: isFull ? 'rgba(239, 68, 68, 0.2)' : 'rgba(34, 197, 94, 0.2)',
borderColor: isFull ? '#ef4444' : '#22c55e'
}
});
return (
<View {...viewProps} style={[styles.dropZone, isFull && styles.fullZone]}>
<Text>Items: {droppedItems.length}/{maxItems}</Text>
{droppedItems.map(item => (
<Text key={item.id} style={styles.item}>{item.title}</Text>
))}
{isFull && <Text style={styles.fullText}>Zone Full</Text>}
</View>
);
}
Aligned Droppable
function AlignedDropZones() {
const alignments: DropAlignment[] = [
'top-left', 'top-center', 'top-right',
'center-left', 'center', 'center-right',
'bottom-left', 'bottom-center', 'bottom-right'
];
return (
<View style={styles.grid}>
{alignments.map(alignment => {
const { viewProps } = useDroppable({
onDrop: (data) => console.log(`Dropped at ${alignment}:`, data),
dropAlignment: alignment,
dropOffset: { x: 5, y: 5 } // Small offset for visual clarity
});
return (
<View key={alignment} {...viewProps} style={styles.alignedZone}>
<Text style={styles.alignmentLabel}>{alignment}</Text>
</View>
);
})}
</View>
);
}
File Upload Droppable
interface FileData {
id: string;
name: string;
size: number;
type: string;
}
function FileUploadZone() {
const [uploadedFiles, setUploadedFiles] = useState<FileData[]>([]);
const { viewProps, isActive } = useDroppable({
onDrop: (file: FileData) => {
setUploadedFiles(prev => [...prev, file]);
uploadFile(file);
},
capacity: 10,
activeStyle: {
backgroundColor: 'rgba(59, 130, 246, 0.1)',
borderColor: '#3b82f6',
borderWidth: 2,
borderStyle: 'dashed' as const
},
onActiveChange: (active) => {
if (active) {
setDropHint('Release to upload');
} else {
setDropHint('Drag files here');
}
}
});
return (
<View {...viewProps} style={[styles.uploadZone, isActive && styles.activeUpload]}>
<Icon name="cloud-upload" size={48} color={isActive ? "#3b82f6" : "#6b7280"} />
<Text style={styles.uploadText}>
{isActive ? "Release to upload" : "Drag files here"}
</Text>
<Text style={styles.fileCount}>
{uploadedFiles.length}/10 files uploaded
</Text>
{uploadedFiles.map(file => (
<View key={file.id} style={styles.fileItem}>
<Text>{file.name}</Text>
<Text style={styles.fileSize}>{formatFileSize(file.size)}</Text>
</View>
))}
</View>
);
}
Conditional Droppable
function ConditionalDropZone({ allowedTypes }: { allowedTypes: string[] }) {
const { viewProps, isActive } = useDroppable({
onDrop: (data: TaskData) => {
if (allowedTypes.includes(data.type)) {
handleValidDrop(data);
} else {
showError(`${data.type} items not allowed here`);
}
},
onActiveChange: (active) => {
// Check if the hovering item is valid
const hoveringItem = getCurrentHoveringItem();
if (active && hoveringItem) {
const isValid = allowedTypes.includes(hoveringItem.type);
setValidDrop(isValid);
}
},
activeStyle: {
backgroundColor: validDrop ? 'rgba(34, 197, 94, 0.2)' : 'rgba(239, 68, 68, 0.2)',
borderColor: validDrop ? '#22c55e' : '#ef4444'
}
});
return (
<View {...viewProps} style={styles.conditionalZone}>
<Text>Accepts: {allowedTypes.join(', ')}</Text>
{isActive && (
<Text style={[styles.feedback, validDrop ? styles.valid : styles.invalid]}>
{validDrop ? "Valid drop target" : "Invalid item type"}
</Text>
)}
</View>
);
}
See Also
- Droppable Component - Component documentation
- useDroppable Hook - Hook documentation
- Draggable Types - Related draggable types
- Context Types - Context-related types