Relationship
A dual-column component for selecting one or more posts, pages, or custom content items with search and filtering capabilities.
Related Posts
Select up to 3 related posts to display
Choose posts that are related to the current content
Getting Started with React
Advanced TypeScript Patterns
Building UIs with Tailwind CSS
State Management Guide
API Design Best Practices
Component Architecture
Installation
CLI
npx shadcn@latest add "https://acfui.com/r/relationship"pnpm dlx shadcn@latest add "https://acfui.com/r/relationship"yarn dlx shadcn@latest add "https://acfui.com/r/relationship"bun x shadcn@latest add "https://acfui.com/r/relationship"Manual
Install the following dependencies:
npm install lucide-react class-variance-authoritypnpm add lucide-react class-variance-authorityyarn add lucide-react class-variance-authoritybun add lucide-react class-variance-authorityCopy and paste the following code into your project.
Update the import paths to match your project setup.
Usage
import { Relationship } from "@/components/ui/relationship"<Relationship
items={posts}
selectedItems={selectedPosts}
onChange={(items) => setSelectedPosts(items)}
multiple={true}
max={5}
/>Examples
Basic
A basic relationship field with static data, search, and filtering capabilities.
Related Posts
Select up to 3 related posts to display
Choose posts that are related to the current content
Getting Started with React
Advanced TypeScript Patterns
Building UIs with Tailwind CSS
State Management Guide
API Design Best Practices
Component Architecture
Async Loading
Load data asynchronously with search and filtering. Perfect for large datasets that need server-side filtering.
Async Content Loader
Search and filter from a large dataset with async loading
Start typing to search through our content database
Single Selection
Configure for single item selection with validation and error handling.
Select the parent page where this content should be nested
Documentation
Main documentation section containing all guides and tutorials
Blog
Blog section with articles and updates
Products
Product catalog and information
About
Company information and team details
Contact
Contact information and support channels
Legal
Legal documents and privacy policy
Advanced Configuration
Comprehensive example showcasing all relationship features with dynamic settings.
Select content items for your collection. Use filters to narrow down results.
React Performance Optimization
Learn advanced techniques to optimize React applications for better performance and user experience...
TypeScript Best Practices
Comprehensive guide to TypeScript best practices and coding patterns for enterprise applications...
CSS Grid Mastery
Master CSS Grid layout with practical examples and real-world use cases...
Next.js 14 Features
Explore the latest features in Next.js 14 and how to use them in your projects...
Database Optimization
Optimize database queries and improve application performance with these proven techniques...
Microservices Architecture
Build scalable microservices architecture with Docker and Kubernetes...
GraphQL API Design
Design efficient GraphQL APIs with proper schema design and resolver patterns...
Testing Strategies
Comprehensive testing strategies for modern web applications...
DevOps Fundamentals
Learn DevOps fundamentals including CI/CD pipelines and infrastructure as code...
Security Best Practices
Essential security best practices for web applications and APIs...
Data Structure
RelationshipItem
The component expects items to follow this structure:
interface RelationshipItem {
id: string | number // Unique identifier
title: string // Display title
type?: string // Content type (post, page, etc.)
status?: "publish" | "draft" | "private" // Publication status
taxonomy?: string[] // Categories, tags, etc.
featured_image?: string // Image URL
excerpt?: string // Short description
date?: string // Publication date
url?: string // Preview URL
}Example Data
const posts: RelationshipItem[] = [
{
id: 1,
title: "Introduction to React Hooks",
type: "post",
status: "publish",
taxonomy: ["React", "JavaScript"],
excerpt: "Learn the fundamentals of React Hooks...",
date: "2024-01-15",
featured_image: "https://example.com/image.jpg",
url: "/posts/react-hooks"
},
// ... more items
]Async Loading
For large datasets, use the onLoad prop to fetch data asynchronously:
const fetchPosts = async (filter: RelationshipFilter): Promise<RelationshipItem[]> => {
const response = await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(filter)
})
return response.json()
}
<Relationship
onLoad={fetchPosts}
selectedItems={selected}
onChange={setSelected}
postTypes={["post", "page"]}
taxonomies={["category", "tag"]}
/>The onLoad function receives a filter object with:
interface RelationshipFilter {
search?: string // Search query
post_type?: string[] // Filter by post types
post_status?: string[] // Filter by post statuses
taxonomy?: string[] // Filter by taxonomies
}Filtering Options
Control which filters are displayed using the showFilters prop:
// Show all filters (default)
<Relationship showFilters={true} />
// Show only search
<Relationship showFilters={["search"]} />
// Show search and post type filters
<Relationship showFilters={["search", "post_type"]} />
// Hide all filters
<Relationship showFilters={false} />Display Options
Customize the item display with various options:
<Relationship
showExcerpt={true} // Show item excerpts
showDate={true} // Show publication dates
showFeaturedImage={true} // Show featured images
showPreview={true} // Show preview links
sortable={true} // Show drag handles (UI ready)
/>Return Formats
Choose how selected items are returned:
// Return full objects (default)
<Relationship
returnFormat="object"
onChange={(items) => {
// items: RelationshipItem[]
console.log(items)
}}
/>
// Return only IDs
<Relationship
returnFormat="id"
onChange={(items) => {
// items: (string | number)[]
console.log(items) // [1, 2, 3]
}}
/>Validation
Add validation rules for selection:
<Relationship
required={true} // Field is required
min={1} // Minimum selections
max={5} // Maximum selections
error="Please select at least one item"
variant="error" // Error styling
/>API Reference
Relationship
| Prop | Type | Default |
|---|---|---|
size? | "sm" | "md" | "lg" | null | - |
variant? | "default" | "error" | null | - |
onTransitionStartCapture? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionStart? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionRunCapture? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionRun? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionEndCapture? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionEnd? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionCancelCapture? | TransitionEventHandler<HTMLDivElement> | - |
onTransitionCancel? | TransitionEventHandler<HTMLDivElement> | - |
onBeforeToggle? | ToggleEventHandler<HTMLDivElement> | - |
onToggle? | ToggleEventHandler<HTMLDivElement> | - |
onAnimationIterationCapture? | AnimationEventHandler<HTMLDivElement> | - |
onAnimationIteration? | AnimationEventHandler<HTMLDivElement> | - |
onAnimationEndCapture? | AnimationEventHandler<HTMLDivElement> | - |
onAnimationEnd? | AnimationEventHandler<HTMLDivElement> | - |
onAnimationStartCapture? | AnimationEventHandler<HTMLDivElement> | - |
onAnimationStart? | AnimationEventHandler<HTMLDivElement> | - |
onWheelCapture? | WheelEventHandler<HTMLDivElement> | - |
onWheel? | WheelEventHandler<HTMLDivElement> | - |
onScrollEndCapture? | UIEventHandler<HTMLDivElement> | - |
onScrollEnd? | UIEventHandler<HTMLDivElement> | - |
onScrollCapture? | UIEventHandler<HTMLDivElement> | - |
onScroll? | UIEventHandler<HTMLDivElement> | - |
onLostPointerCaptureCapture? | PointerEventHandler<HTMLDivElement> | - |
onLostPointerCapture? | PointerEventHandler<HTMLDivElement> | - |
onGotPointerCaptureCapture? | PointerEventHandler<HTMLDivElement> | - |
onGotPointerCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerOutCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerOut? | PointerEventHandler<HTMLDivElement> | - |
onPointerOverCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerOver? | PointerEventHandler<HTMLDivElement> | - |
onPointerLeave? | PointerEventHandler<HTMLDivElement> | - |
onPointerEnter? | PointerEventHandler<HTMLDivElement> | - |
onPointerCancelCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerCancel? | PointerEventHandler<HTMLDivElement> | - |
onPointerUpCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerUp? | PointerEventHandler<HTMLDivElement> | - |
onPointerMoveCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerMove? | PointerEventHandler<HTMLDivElement> | - |
onPointerDownCapture? | PointerEventHandler<HTMLDivElement> | - |
onPointerDown? | PointerEventHandler<HTMLDivElement> | - |
onTouchStartCapture? | TouchEventHandler<HTMLDivElement> | - |
onTouchStart? | TouchEventHandler<HTMLDivElement> | - |
onTouchMoveCapture? | TouchEventHandler<HTMLDivElement> | - |
onTouchMove? | TouchEventHandler<HTMLDivElement> | - |
onTouchEndCapture? | TouchEventHandler<HTMLDivElement> | - |
onTouchEnd? | TouchEventHandler<HTMLDivElement> | - |
onTouchCancelCapture? | TouchEventHandler<HTMLDivElement> | - |
onTouchCancel? | TouchEventHandler<HTMLDivElement> | - |
onSelectCapture? | ReactEventHandler<HTMLDivElement> | - |
onMouseUpCapture? | MouseEventHandler<HTMLDivElement> | - |
onMouseUp? | MouseEventHandler<HTMLDivElement> | - |
onMouseOverCapture? | MouseEventHandler<HTMLDivElement> | - |
onMouseOver? | MouseEventHandler<HTMLDivElement> | - |
onMouseOutCapture? | MouseEventHandler<HTMLDivElement> | - |
onMouseOut? | MouseEventHandler<HTMLDivElement> | - |
onMouseMoveCapture? | MouseEventHandler<HTMLDivElement> | - |
onMouseMove? | MouseEventHandler<HTMLDivElement> | - |
onMouseLeave? | MouseEventHandler<HTMLDivElement> | - |
onMouseEnter? | MouseEventHandler<HTMLDivElement> | - |
onMouseDownCapture? | MouseEventHandler<HTMLDivElement> | - |
onMouseDown? | MouseEventHandler<HTMLDivElement> | - |
onDropCapture? | DragEventHandler<HTMLDivElement> | - |
onDrop? | DragEventHandler<HTMLDivElement> | - |
onDragStartCapture? | DragEventHandler<HTMLDivElement> | - |
onDragStart? | DragEventHandler<HTMLDivElement> | - |
onDragOverCapture? | DragEventHandler<HTMLDivElement> | - |
onDragOver? | DragEventHandler<HTMLDivElement> | - |
onDragLeaveCapture? | DragEventHandler<HTMLDivElement> | - |
onDragLeave? | DragEventHandler<HTMLDivElement> | - |
onDragExitCapture? | DragEventHandler<HTMLDivElement> | - |
onDragExit? | DragEventHandler<HTMLDivElement> | - |
onDragEnterCapture? | DragEventHandler<HTMLDivElement> | - |
onDragEnter? | DragEventHandler<HTMLDivElement> | - |
onDragEndCapture? | DragEventHandler<HTMLDivElement> | - |
onDragEnd? | DragEventHandler<HTMLDivElement> | - |
onDragCapture? | DragEventHandler<HTMLDivElement> | - |
onDrag? | DragEventHandler<HTMLDivElement> | - |
onDoubleClickCapture? | MouseEventHandler<HTMLDivElement> | - |
onDoubleClick? | MouseEventHandler<HTMLDivElement> | - |
onContextMenuCapture? | MouseEventHandler<HTMLDivElement> | - |
onContextMenu? | MouseEventHandler<HTMLDivElement> | - |
onClickCapture? | MouseEventHandler<HTMLDivElement> | - |
onClick? | MouseEventHandler<HTMLDivElement> | - |
onAuxClickCapture? | MouseEventHandler<HTMLDivElement> | - |
onAuxClick? | MouseEventHandler<HTMLDivElement> | - |
onWaitingCapture? | ReactEventHandler<HTMLDivElement> | - |
onWaiting? | ReactEventHandler<HTMLDivElement> | - |
onVolumeChangeCapture? | ReactEventHandler<HTMLDivElement> | - |
onVolumeChange? | ReactEventHandler<HTMLDivElement> | - |
onTimeUpdateCapture? | ReactEventHandler<HTMLDivElement> | - |
onTimeUpdate? | ReactEventHandler<HTMLDivElement> | - |
onSuspendCapture? | ReactEventHandler<HTMLDivElement> | - |
onSuspend? | ReactEventHandler<HTMLDivElement> | - |
onStalledCapture? | ReactEventHandler<HTMLDivElement> | - |
onStalled? | ReactEventHandler<HTMLDivElement> | - |
onSeekingCapture? | ReactEventHandler<HTMLDivElement> | - |
onSeeking? | ReactEventHandler<HTMLDivElement> | - |
onSeekedCapture? | ReactEventHandler<HTMLDivElement> | - |
onSeeked? | ReactEventHandler<HTMLDivElement> | - |
onRateChangeCapture? | ReactEventHandler<HTMLDivElement> | - |
onRateChange? | ReactEventHandler<HTMLDivElement> | - |
onProgressCapture? | ReactEventHandler<HTMLDivElement> | - |
onProgress? | ReactEventHandler<HTMLDivElement> | - |
onPlayingCapture? | ReactEventHandler<HTMLDivElement> | - |
onPlaying? | ReactEventHandler<HTMLDivElement> | - |
onPlayCapture? | ReactEventHandler<HTMLDivElement> | - |
onPlay? | ReactEventHandler<HTMLDivElement> | - |
onPauseCapture? | ReactEventHandler<HTMLDivElement> | - |
onPause? | ReactEventHandler<HTMLDivElement> | - |
onLoadStartCapture? | ReactEventHandler<HTMLDivElement> | - |
onLoadStart? | ReactEventHandler<HTMLDivElement> | - |
onLoadedMetadataCapture? | ReactEventHandler<HTMLDivElement> | - |
onLoadedMetadata? | ReactEventHandler<HTMLDivElement> | - |
onLoadedDataCapture? | ReactEventHandler<HTMLDivElement> | - |
onLoadedData? | ReactEventHandler<HTMLDivElement> | - |
onEndedCapture? | ReactEventHandler<HTMLDivElement> | - |
onEnded? | ReactEventHandler<HTMLDivElement> | - |
onEncryptedCapture? | ReactEventHandler<HTMLDivElement> | - |
onEncrypted? | ReactEventHandler<HTMLDivElement> | - |
onEmptiedCapture? | ReactEventHandler<HTMLDivElement> | - |
onEmptied? | ReactEventHandler<HTMLDivElement> | - |
onDurationChangeCapture? | ReactEventHandler<HTMLDivElement> | - |
onDurationChange? | ReactEventHandler<HTMLDivElement> | - |
onCanPlayThroughCapture? | ReactEventHandler<HTMLDivElement> | - |
onCanPlayThrough? | ReactEventHandler<HTMLDivElement> | - |
onCanPlayCapture? | ReactEventHandler<HTMLDivElement> | - |
onCanPlay? | ReactEventHandler<HTMLDivElement> | - |
onAbortCapture? | ReactEventHandler<HTMLDivElement> | - |
onAbort? | ReactEventHandler<HTMLDivElement> | - |
onKeyUpCapture? | KeyboardEventHandler<HTMLDivElement> | - |
onKeyUp? | KeyboardEventHandler<HTMLDivElement> | - |
onKeyDownCapture? | KeyboardEventHandler<HTMLDivElement> | - |
onKeyDown? | KeyboardEventHandler<HTMLDivElement> | - |
onErrorCapture? | ReactEventHandler<HTMLDivElement> | - |
onError? | ReactEventHandler<HTMLDivElement> | - |
onLoadCapture? | ReactEventHandler<HTMLDivElement> | - |
onInvalidCapture? | FormEventHandler<HTMLDivElement> | - |
onInvalid? | FormEventHandler<HTMLDivElement> | - |
onSubmitCapture? | FormEventHandler<HTMLDivElement> | - |
onSubmit? | FormEventHandler<HTMLDivElement> | - |
onResetCapture? | FormEventHandler<HTMLDivElement> | - |
onReset? | FormEventHandler<HTMLDivElement> | - |
onInputCapture? | FormEventHandler<HTMLDivElement> | - |
onInput? | FormEventHandler<HTMLDivElement> | - |
onBeforeInputCapture? | FormEventHandler<HTMLDivElement> | - |
onBeforeInput? | InputEventHandler<HTMLDivElement> | - |
onChangeCapture? | FormEventHandler<HTMLDivElement> | - |
onBlurCapture? | FocusEventHandler<HTMLDivElement> | - |
onBlur? | FocusEventHandler<HTMLDivElement> | - |
onFocusCapture? | FocusEventHandler<HTMLDivElement> | - |
onFocus? | FocusEventHandler<HTMLDivElement> | - |
onCompositionUpdateCapture? | CompositionEventHandler<HTMLDivElement> | - |
onCompositionUpdate? | CompositionEventHandler<HTMLDivElement> | - |
onCompositionStartCapture? | CompositionEventHandler<HTMLDivElement> | - |
onCompositionStart? | CompositionEventHandler<HTMLDivElement> | - |
onCompositionEndCapture? | CompositionEventHandler<HTMLDivElement> | - |
onCompositionEnd? | CompositionEventHandler<HTMLDivElement> | - |
onPasteCapture? | ClipboardEventHandler<HTMLDivElement> | - |
onPaste? | ClipboardEventHandler<HTMLDivElement> | - |
onCutCapture? | ClipboardEventHandler<HTMLDivElement> | - |
onCut? | ClipboardEventHandler<HTMLDivElement> | - |
onCopyCapture? | ClipboardEventHandler<HTMLDivElement> | - |
onCopy? | ClipboardEventHandler<HTMLDivElement> | - |
dangerouslySetInnerHTML? | { __html: string | TrustedHTML; } | - |
children? | ReactNode | - |
aria-valuetext? | string | - |
aria-valuenow? | number | - |
aria-valuemin? | number | - |
aria-valuemax? | number | - |
aria-sort? | "none" | "ascending" | "descending" | "other" | - |
aria-setsize? | number | - |
aria-selected? | Booleanish | - |
aria-rowspan? | number | - |
aria-rowindextext? | string | - |
aria-rowindex? | number | - |
aria-rowcount? | number | - |
aria-roledescription? | string | - |
aria-required? | Booleanish | - |
aria-relevant? | "text" | "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text additions" | "text removals" | - |
aria-readonly? | Booleanish | - |
aria-pressed? | boolean | "true" | "false" | "mixed" | - |
aria-posinset? | number | - |
aria-placeholder? | string | - |
aria-owns? | string | - |
aria-orientation? | "horizontal" | "vertical" | - |
aria-multiselectable? | Booleanish | - |
aria-multiline? | Booleanish | - |
aria-modal? | Booleanish | - |
aria-live? | "off" | "assertive" | "polite" | - |
aria-level? | number | - |
aria-labelledby? | string | - |
aria-label? | string | - |
aria-keyshortcuts? | string | - |
aria-invalid? | boolean | "true" | "false" | "grammar" | "spelling" | - |
aria-hidden? | Booleanish | - |
aria-haspopup? | boolean | "true" | "false" | "dialog" | "grid" | "listbox" | "menu" | "tree" | - |
aria-flowto? | string | - |
aria-expanded? | Booleanish | - |
aria-errormessage? | string | - |
aria-disabled? | Booleanish | - |
aria-details? | string | - |
aria-description? | string | - |
aria-describedby? | string | - |
aria-current? | boolean | "true" | "false" | "page" | "step" | "location" | "date" | "time" | - |
aria-controls? | string | - |
aria-colspan? | number | - |
aria-colindextext? | string | - |
aria-colindex? | number | - |
aria-colcount? | number | - |
aria-checked? | boolean | "true" | "false" | "mixed" | - |
aria-busy? | Booleanish | - |
aria-brailleroledescription? | string | - |
aria-braillelabel? | string | - |
aria-autocomplete? | "none" | "list" | "inline" | "both" | - |
aria-atomic? | Booleanish | - |
aria-activedescendant? | string | - |
part? | string | - |
exportparts? | string | - |
is? | string | - |
inputMode? | "none" | "search" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | - |
inert? | boolean | - |
popoverTarget? | string | - |
popoverTargetAction? | "toggle" | "show" | "hide" | - |
popover? | "" | "auto" | "manual" | - |
unselectable? | "off" | "on" | - |
security? | string | - |
results? | number | - |
itemRef? | string | - |
itemID? | string | - |
itemType? | string | - |
itemScope? | boolean | - |
itemProp? | string | - |
color? | string | - |
autoSave? | string | - |
autoCorrect? | string | - |
vocab? | string | - |
typeof? | string | - |
rev? | string | - |
resource? | string | - |
rel? | string | - |
property? | string | - |
prefix? | string | - |
inlist? | any | - |
datatype? | string | - |
content? | string | - |
about? | string | - |
role? | AriaRole | - |
radioGroup? | string | - |
translate? | "yes" | "no" | - |
title? | string | - |
tabIndex? | number | - |
style? | CSSProperties | - |
spellCheck? | Booleanish | - |
slot? | string | - |
nonce? | string | - |
lang? | string | - |
id? | string | - |
hidden? | boolean | - |
enterKeyHint? | "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | - |
draggable? | Booleanish | - |
dir? | string | - |
contextMenu? | string | - |
contentEditable? | Booleanish | "inherit" | "plaintext-only" | - |
className? | string | - |
autoFocus? | boolean | - |
autoCapitalize? | "off" | "none" | "on" | "sentences" | "words" | "characters" | (string & {}) | - |
accessKey? | string | - |
suppressHydrationWarning? | boolean | - |
suppressContentEditableWarning? | boolean | - |
defaultValue? | string | number | readonly string[] | - |
defaultChecked? | boolean | - |
error? | string | - |
instructions? | string | - |
loadingText? | string | - |
noSelectedText? | string | - |
noItemsText? | string | - |
searchPlaceholder? | string | - |
onRemove? | ((item: RelationshipItem) => void) | - |
onSelect? | ((item: RelationshipItem) => void) | - |
onChange? | ((items: RelationshipItem[] | string[] | number[]) => void) | - |
returnFormat? | "object" | "id" | - |
sortable? | boolean | - |
showDate? | boolean | - |
showExcerpt? | boolean | - |
showFeaturedImage? | boolean | - |
showPreview? | boolean | - |
showFilters? | boolean | string[] | - |
taxonomies? | string[] | - |
postStatuses? | string[] | - |
postTypes? | string[] | - |
loading? | boolean | - |
onLoad? | ((filter: RelationshipFilter) => Promise<RelationshipItem[]>) | - |
required? | boolean | - |
max? | number | - |
min? | number | - |
multiple? | boolean | - |
selectedItems? | RelationshipItem[] | - |
items? | RelationshipItem[] | - |
aria-dropeffect? | "none" | "link" | "copy" | "execute" | "move" | "popup" | - |
aria-grabbed? | Booleanish | - |
onKeyPress? | KeyboardEventHandler<HTMLDivElement> | - |
onKeyPressCapture? | KeyboardEventHandler<HTMLDivElement> | - |
RelationshipItem Interface
interface RelationshipItem {
id: string | number // Unique identifier
title: string // Display title
type?: string // Post type (post, page, etc.)
status?: "publish" | "draft" | "private" // Publication status
taxonomy?: string[] // Categories, tags, etc.
featured_image?: string // Image URL
excerpt?: string // Short description
date?: string // Publication date
url?: string // Preview URL
}RelationshipFilter Interface
interface RelationshipFilter {
search?: string // Search query
post_type?: string[] // Filter by post types
post_status?: string[] // Filter by post statuses
taxonomy?: string[] // Filter by taxonomies
}Event Handlers
| Prop | Type | Description |
|---|---|---|
onChange | (items: RelationshipItem[] | string[] | number[]) => void | Called when selection changes |
onSelect | (item: RelationshipItem) => void | Called when an item is selected |
onRemove | (item: RelationshipItem) => void | Called when an item is removed |
onLoad | (filter: RelationshipFilter) => Promise<RelationshipItem[]> | Async data loading function |
Configuration Props
| Prop | Type | Default | Description |
|---|---|---|---|
multiple | boolean | true | Allow multiple selections |
min | number | 0 | Minimum required selections |
max | number | 10 | Maximum allowed selections |
required | boolean | false | Whether field is required |
returnFormat | "object" | "id" | "object" | Format of returned data |
Display Props
| Prop | Type | Default | Description |
|---|---|---|---|
showExcerpt | boolean | false | Show item excerpts |
showDate | boolean | false | Show item dates |
showFeaturedImage | boolean | false | Show featured images |
showPreview | boolean | false | Show preview links |
sortable | boolean | false | Show drag handles for sorting |
Filter Props
| Prop | Type | Default | Description |
|---|---|---|---|
postTypes | string[] | [] | Available post types for filtering |
postStatuses | string[] | [] | Available post statuses for filtering |
taxonomies | string[] | [] | Available taxonomies for filtering |
showFilters | boolean | string[] | true | Which filters to show |
Text Props
| Prop | Type | Default | Description |
|---|---|---|---|
searchPlaceholder | string | "Search..." | Search input placeholder |
noItemsText | string | "No items found" | Text when no items available |
noSelectedText | string | "No items selected" | Text when nothing selected |
loadingText | string | "Loading..." | Loading state text |
instructions | string | - | Instructions text at top |
Styling Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "error" | "default" | Visual variant |
size | "sm" | "md" | "lg" | "md" | Size variant |
error | string | - | Error message to display |
Common Patterns
Content Management System
const [parentPage, setParentPage] = useState(null)
<Relationship
items={pages}
selectedItems={parentPage ? [parentPage] : []}
onChange={(items) => setParentPage(items[0] || null)}
multiple={false}
max={1}
required={true}
showFilters={["search"]}
error={errors.parent_page}
/>E-commerce Related Products
const [relatedProducts, setRelatedProducts] = useState([])
<Relationship
onLoad={fetchProducts}
selectedItems={relatedProducts}
onChange={setRelatedProducts}
postTypes={["product"]}
taxonomies={["product_cat", "product_tag"]}
showFeaturedImage={true}
showExcerpt={true}
max={8}
returnFormat="id"
/>Blog Post Relations
const [relatedPosts, setRelatedPosts] = useState([])
<Relationship
onLoad={async (filter) => {
const response = await fetch('/api/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(filter)
})
return response.json()
}}
selectedItems={relatedPosts}
onChange={setRelatedPosts}
postTypes={["post", "page", "article"]}
taxonomies={["category", "tag"]}
showExcerpt={true}
showFeaturedImage={true}
max={5}
/>Accessibility
The Relationship component follows accessibility best practices:
- Keyboard Navigation - Full keyboard support for all interactions
- Screen Reader Support - Proper ARIA labels and descriptions
- Focus Management - Clear focus indicators and logical tab order
- High Contrast - Supports high contrast mode
- Reduced Motion - Respects
prefers-reduced-motionsettings
Keyboard Interactions
| Key | Description |
|---|---|
Tab | Move focus between interface elements |
Enter | Select/deselect items |
Escape | Clear focus from filters |
Arrow Keys | Navigate through available items |