content/guides/02.content/9.collaborative-editing/3.development.md
Collaborative Editing works out-of-the-box for most Custom Interfaces.
Unlike the previous extension-based implementation, you do not need to add specific data attributes to your components. The system automatically handles presence, field locking, and synchronization through the v-form and form-field wrappers.
When your Custom Interface is rendered within a Directus Form:
form-field component.focusin and focusout events bubbling up from your component.For your custom interface to fully support collaborative editing, ensure the following:
Your component should allow focus and blur (or focusin/focusout) events to bubble up to the parent. This is standard behavior for native HTML inputs (<input>, <textarea>, etc.).
Ensure your component emits the update:modelValue event when data changes, as per standard Vue 3 component design. This ensures real-time updates are propagated to other connected users.
emit('update:modelValue', newValue);
Respect the disabled prop. When a field is locked by another user, Directus passes disabled: true to your interface. Ensure your component visually reflects this state and prevents user interaction.
defineProps({
disabled: {
type: Boolean,
default: false,
},
// ...
});
If your interface is not triggering the "locked" state for other users:
event.stopPropagation() on focus events, the wrapper will not detect the user's presence.tabindex if it's not a native input).Directus provides built-in utilities to help manage focus states in complex interfaces.
v-prevent-focusout DirectiveUse this directive to prevent the focusout event from bubbling when interacting with specific elements (like dropdowns, modals, or drawers) that are part of your interface but might technically sit outside the DOM hierarchy or trigger a blur.
<!-- Prevents losing the "locked" state when clicking inside this drawer -->
<v-drawer v-prevent-focusout="isOpen" ...>
...
</v-drawer>
useFocusin ComposableIf your component doesn't have a native input to trigger focus (e.g., a purely visual selector), you can use useFocusin to manually dispatch focus events.
import { useFocusin } from '@/composables/use-focusin';
const { active, focus, blur } = useFocusin(containerRef);
// Manually trigger
focus();
If you are building complex interfaces that do not rely on standard focus events (e.g., a canvas-based editor), you may need to manually trigger focus events or manage the disabled state more aggressively. However, for most use cases, no specific "Collaborative Editing" code is required.