A powerful, production-ready M2A (Many-to-Any) interface extension for Directus with inline expandable editing, advanced item selection, comprehensive permissions, and seamless integration with Directus' native save system. Also provides reusable ItemSelector components for other extensions.
π Documentation β’ π Report Bug β’ β¨ Request Feature β’ π¦ NPM Package
- Why Expandable Blocks?
- Features
- Installation
- Usage
- Configuration
- Shared Components
- Testing
- Development
- Documentation
- Contributing
- License
Unlike other block editors, this extension works directly with Directus' native form system and provides unique killer features:
- π Reference Tracking - See EVERYWHERE an item is used across your entire system
- π Link or Copy - Choose to reference existing items or create independent copies
β οΈ Usage Protection - Never accidentally delete content that's used elsewhere
- Native Save & Stay - Works perfectly with Directus' save options
- Global Discard - Integrates with Directus' "Discard Changes" button
- Proper Dirty State - Save button only appears when changes exist
- No Data Loss - All changes tracked through Directus' form state
- Enterprise Ready - Production-tested with comprehensive permissions
- 100% Test Coverage - 470 unit tests ensuring reliability
- π Inline Expandable Editing - Edit content without opening separate forms
- π― Drag & Drop Sorting - Intuitive block reordering with visual feedback
- π Visual NEW Indicator - See unsaved blocks at a glance
- π Status Management - Quick status changes with color-coded indicators
- π Duplicate Blocks - Clone existing blocks with one click
- ποΈ Smart Delete - Unlink or permanently delete with confirmation
- π Discard Changes - Revert individual blocks to original state
- π Advanced Item Selector - Select and link existing items from any collection
- π Link or Copy Mode - Choose to reference existing items or create copies
- π Table View - Browse items in a sortable, filterable table
- π·οΈ Tag-Based Search - Search with AND/OR operators and field-specific queries
- π― Smart Search - Simple search mode with optional advanced tag search
- π Search Highlighting - See matching terms highlighted in results
- π Search History - Remember and reuse previous searches
- π Result Count - See number of matching items instantly
- π Intelligent Columns - Auto-sizing based on field types
- π Sticky Columns - Keep important columns visible while scrolling
βοΈ Sortable Headers - Sort by any field with 3-click cycle- π¨ Field Display - Smart rendering for all Directus field types
- πΌοΈ Image Preview - Hover to see full images
- π WYSIWYG Support - Automatic HTML stripping for clean display
- β‘ Virtual Scrolling - Handle thousands of items efficiently
- π Multi-Language - Full support for Directus translations
- π Language Switching - Change languages on the fly
- π Translation Search - Search across all language versions
- π·οΈ Language Indicators - See which fields are translatable
- π Directus Permissions - Respects all native permissions
- π₯ Role-Based Control - Configure per-role access
- π Read-Only Mode - Automatic for restricted items
β οΈ Permission Indicators - Visual feedback for restricted actions- π‘οΈ Security - Built-in validation and permission checks
- π Reference Detection - Instantly see ALL places where an item is used across your entire Directus instance
- π Cross-Collection References - Track usage across different collections and relationships
- π Deep Links - Navigate directly to parent items with one click
β οΈ Usage Warnings - Get alerts before deleting items that are referenced elsewhere- π Usage Paths - Visual breadcrumbs showing complete relationship chains
- π― Smart Prevention - Prevents accidental deletion of referenced content
Note: These features require the optional API extension to be installed.
- βοΈ Edit Drawer - Edit items without leaving the interface
- πΎ Independent Saves - Save edits without affecting main form
- π Live Updates - See changes reflected immediately
- π Adjustable Width - Resize drawer to your preference
- π Multi-Layer Caching - Configurable TTLs for optimal speed
- π Smart Loading - Load only what's needed
- π Debounced Operations - Prevent excessive API calls
- β‘ Optimized Re-renders - Using Vue 3's advanced features
- πΎ Persistent Preferences - Remember user settings
- β 100% Test Coverage - 470 passing unit tests
- π― TypeScript Strict Mode - Zero type errors
- π ESLint Compliant - Zero linting errors
- ποΈ Modular Architecture - 15+ reusable components
- π Comprehensive Docs - Wiki, API docs, and inline comments
- π¦ Interface Extension - Clean, focused interface implementation
- π Composable Architecture - Reusable Vue composables
- π¨ Component Library - Modular, tested components
- π§ Utility Functions - Shared helpers and validators
- π TypeScript Types - Full type definitions
# Install the interface extension
npm install directus-extension-expandable-blocks
# Optional: Install the API extension for advanced usage tracking
npm install directus-extension-expandable-blocks-api
# Install the interface extension
pnpm add directus-extension-expandable-blocks
# Optional: Install the API extension for advanced usage tracking
pnpm add directus-extension-expandable-blocks-api
- Download the latest release from GitHub Releases
- Extract to your Directus
extensions/
directory - Restart Directus
- Optional: Install the API extension for usage tracking
# Install the interface extension
RUN npm install directus-extension-expandable-blocks
# Optional: Install the API extension for advanced usage tracking
RUN npm install directus-extension-expandable-blocks-api
The API extension is now a separate, optional package. The core Expandable Blocks interface works perfectly without it, using Directus' native API for all standard operations.
- β You want to see where items are used before deleting them
- β You need to track references across M2A relationships
- β You want protection against accidentally deleting referenced content
- β All core features (editing, sorting, adding blocks) work normally
- β Uses native Directus API for all operations
β οΈ Cannot verify item usage before deletion (shows warning instead)
- Navigate to Settings β Data Model β [Your Collection]
- Click "Create Field"
- Choose "Many to Any Relationship (M2A)"
- Configure the relationship
- In the field configuration, go to "Interface" tab
- Select "Expandable Blocks" from the dropdown
- Configure your options
The interface provides extensive configuration grouped into logical sections:
- Display Options - Visual preferences
- Permissions & Actions - What users can do
- Collections & Relations - Available collections
- Advanced Settings - Caching, translations, etc.
Option | Type | Default | Description |
---|---|---|---|
enableSorting |
boolean | true |
Enable drag & drop reordering |
showItemId |
boolean | true |
Display item IDs |
showCollectionName |
boolean | true |
Show collection type |
startExpanded |
boolean | false |
Start with blocks expanded |
accordionMode |
boolean | false |
One block open at a time |
compactMode |
boolean | false |
Condensed view |
Option | Type | Default | Description |
---|---|---|---|
isAllowedDelete |
boolean | true |
Allow deletion |
isAllowedDuplicate |
boolean | true |
Allow duplication |
allowLinkExisting |
boolean | true |
Allow linking existing |
allowDuplicateExisting |
boolean | true |
Allow duplicating linked |
maxBlocks |
number | null |
Maximum blocks allowed |
Option | Type | Default | Description |
---|---|---|---|
collection |
array | [] |
Collections for new blocks |
allowedCollectionsExisting |
array | [] |
Collections for existing items |
Option | Type | Default | Description |
---|---|---|---|
enableCache |
boolean | true |
Enable API caching |
enableTranslations |
boolean | true |
Support translations |
showUsageWarnings |
boolean | true |
Show usage indicators |
Configure caching behavior:
# Cache TTL Settings (in minutes)
EXPANDABLE_BLOCKS_CACHE_TTL_METADATA=30
EXPANDABLE_BLOCKS_CACHE_TTL_SEARCH=5
EXPANDABLE_BLOCKS_CACHE_TTL_DETAIL=10
EXPANDABLE_BLOCKS_CACHE_TTL_PATHS=10
# Maximum cache size
EXPANDABLE_BLOCKS_CACHE_MAX_SIZE=50000
This extension provides reusable ItemSelector components that can be used in other Directus extensions, allowing you to avoid code duplication and maintain consistent UX across extensions.
# Add as dependency to your extension
npm install directus-extension-expandable-blocks
// Import shared components in your extension
import {
useItemSelector,
ItemSelectorDrawer,
type ItemSelectorConfig
} from 'directus-extension-expandable-blocks/shared';
// Configure for your extension
const itemSelector = useItemSelector(api, ['pages', 'articles'], {
loggerPrefix: '[MyExtension]',
allowLink: true,
allowDuplicate: false,
collectionIcons: {
'pages': 'description',
'articles': 'article'
}
});
useItemSelector
- Core composable with all functionalityItemSelectorDrawer
- Main selector interfaceItemSearchPanel
- Advanced search with operatorsFieldDisplay
- Field value display componentUsagePopover
- Shows item usage across collections
interface ItemSelectorConfig {
loggerPrefix?: string; // Custom logging prefix
allowLink?: boolean; // Allow linking items
allowDuplicate?: boolean; // Allow duplicating items
defaultItemsPerPage?: number; // Pagination size
defaultLanguage?: string; // Translation language
collectionIcons?: Record<string, string>; // Custom icons
fieldMappings?: Record<string, string>; // Field name mappings
debug?: boolean; // Enable debug logging
}
π Complete Shared Components Documentation - Detailed usage guide, examples, and API reference for extension developers.
<template>
<ItemSelectorDrawer
:open="itemSelector.isOpen.value"
:collection="itemSelector.selectedCollection.value"
:items="itemSelector.availableItems.value"
:loading="itemSelector.loading.value"
:logger-prefix="'[LayoutBlocks]'"
@close="itemSelector.close"
@confirm="handleItemsSelected"
/>
</template>
<script setup>
import { useItemSelector, ItemSelectorDrawer } from 'directus-extension-expandable-blocks/shared';
const itemSelector = useItemSelector(api, ['layouts'], {
loggerPrefix: '[LayoutBlocks]',
allowDuplicate: false
});
</script>
# Run all tests (100% coverage)
npm run test -- --run
# Test with UI
npm run test:ui
# Coverage report
npm run test:coverage
# Type checking
npm run type-check
# Linting
npm run lint
- β 470 unit tests - All passing
- β 100% coverage - Full test coverage
- β 0 TypeScript errors - Strict mode compliant
- β 0 ESLint errors - Clean code
# Install dependencies (we use pnpm)
pnpm install
# Development mode
npm run dev
# Production build
npm run build
# Type checking
npm run type-check
# Create demo videos
npm run demo:product
npm run demo:highlights
expandable-blocks/
βββ config/ # Configuration files
β βββ scripts/ # Build scripts
β βββ *.config.* # Various configs
βββ src/
β βββ components/ # Vue components
β βββ composables/ # Vue composables
β βββ types/ # TypeScript types
β βββ utils/ # Utilities
βββ test/ # Test files
βββ wiki/ # Documentation
Visit our GitHub Wiki for:
- π Getting Started
- π¦ Installation Guide
- βοΈ Configuration
- ποΈ Architecture
- π Security
- π Advanced Features
- π¬ Demo Videos
- β‘ Cache Configuration
We welcome contributions! Please see our Contributing Guide for details.
MIT License - see LICENSE file for details
Made with β€οΈ for the Directus community
- 200+ commits of continuous improvement
- 15+ components for modular architecture
- 470 tests ensuring reliability
- 0 errors in TypeScript and ESLint
- 100% coverage for peace of mind
Ready for production use! π