Post Object
A dropdown component for selecting one or more posts, pages, or custom content items with search and filtering capabilities.
Featured Post
Select a post to feature on the homepage
Installation
CLI
npx shadcn@latest add "https://acfui.com/r/post-object"pnpm dlx shadcn@latest add "https://acfui.com/r/post-object"yarn dlx shadcn@latest add "https://acfui.com/r/post-object"bun x shadcn@latest add "https://acfui.com/r/post-object"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 { PostObject } from "@/components/ui/post-object"<PostObject
items={posts}
selectedItems={selectedPosts}
onChange={(items) => setSelectedPosts(items)}
placeholder="Select posts..."
allowNull
/>Examples
Basic
A basic post object field with static data and search functionality.
Featured Post
Select a post to feature on the homepage
Multiple Selection
Configure for multiple post selection with filters and sortable display.
Related Content
Select up to 5 related posts to display in the sidebar
Choose posts that are related to the current content. You can select up to 5 posts.
Async Loading
Load posts dynamically with search and filtering. Perfect for large datasets.
Dynamic Content Loader
Search and filter from a large dataset with async loading
Start typing to search through our content database
Data Structure
PostObjectItem
The component expects items to follow this structure:
interface PostObjectItem {
id: string | number
title: string
type?: string
status?: "publish" | "draft" | "private"
taxonomy?: string[]
featured_image?: string
excerpt?: string
date?: string
url?: string
}Example Data
const posts: PostObjectItem[] = [
{
id: 1,
title: "Getting Started with React",
type: "post",
status: "publish",
taxonomy: ["React", "JavaScript"],
excerpt: "Learn the basics of React development...",
date: "2024-01-15",
url: "/posts/getting-started-react"
},
// ... more items
]Async Loading
For large datasets, use the onLoad prop to fetch data asynchronously:
const fetchPosts = async (filter: PostObjectFilter): Promise<PostObjectItem[]> => {
const response = await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(filter)
})
return response.json()
}
<PostObject
onLoad={fetchPosts}
selectedItems={selected}
onChange={setSelected}
postTypes={["post", "page"]}
postStatuses={["publish", "draft"]}
showFilters={["search", "post_type"]}
/>Filtering Options
Control which filters are displayed using the showFilters prop:
// Show all filters
<PostObject showFilters={true} />
// Show only search
<PostObject showFilters={["search"]} />
// Show search and post type filters
<PostObject showFilters={["search", "post_type"]} />
// Hide all filters
<PostObject showFilters={false} />Return Formats
Choose how selected items are returned:
// Return full objects (default)
<PostObject
returnFormat="object"
onChange={(items) => {
// items: PostObjectItem[]
console.log(items)
}}
/>
// Return only IDs
<PostObject
returnFormat="id"
onChange={(items) => {
// items: (string | number)[]
console.log(items) // [1, 2, 3]
}}
/>Configuration Options
Single vs Multiple Selection
// Single selection (default)
<PostObject
multiple={false}
placeholder="Select a post..."
onChange={(items) => {
const post = items[0] // Single item
}}
/>
// Multiple selection
<PostObject
multiple={true}
placeholder="Select posts..."
sortable={true} // Enable drag-and-drop reordering
onChange={(items) => {
// Array of items
}}
/>Allow Null Option
<PostObject
allowNull={true} // Show "Clear selection" option
required={false} // Not required
placeholder="Select a post (optional)..."
/>API Reference
PostObject
| Prop | Type | Default | Description |
|---|---|---|---|
items | PostObjectItem[] | [] | Static items to display |
selectedItems | PostObjectItem[] | [] | Currently selected items |
onChange | (items: PostObjectItem[] | string[] | number[] | null) => void | - | Callback when selection changes |
onLoad | (filter: PostObjectFilter) => Promise<PostObjectItem[]> | - | Async data loading function |
multiple | boolean | false | Allow multiple selections |
allowNull | boolean | true | Allow clearing selections |
required | boolean | false | Whether field is required |
postTypes | string[] | [] | Available post types for filtering |
postStatuses | string[] | [] | Available post statuses for filtering |
taxonomies | string[] | [] | Available taxonomies for filtering |
showFilters | boolean | string[] | false | Which filters to show |
showPreview | boolean | false | Show preview links |
showFeaturedImage | boolean | false | Show featured images |
showExcerpt | boolean | false | Show item excerpts |
showDate | boolean | false | Show item dates |
sortable | boolean | false | Enable drag-and-drop sorting |
returnFormat | "object" | "id" | "object" | Format of returned data |
placeholder | string | "Select post..." | Dropdown placeholder text |
searchPlaceholder | string | "Search posts..." | Search input placeholder |
noItemsText | string | "No posts found" | Text when no items available |
loadingText | string | "Loading..." | Loading state text |
instructions | string | - | Help text above the field |
error | string | - | Error message to display |
variant | "default" | "error" | "default" | Visual variant |
size | "sm" | "md" | "lg" | "md" | Size variant |
Event Handlers
| Prop | Type | Description |
|---|---|---|
onSelect | (item: PostObjectItem) => void | Called when an item is selected |
onRemove | (item: PostObjectItem) => void | Called when an item is removed |
PostObjectItem Interface
interface PostObjectItem {
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
}PostObjectFilter Interface
interface PostObjectFilter {
search?: string // Search query
post_type?: string[] // Filter by post types
post_status?: string[] // Filter by post statuses
taxonomy?: string[] // Filter by taxonomies
}Common Patterns
Content Management System
const [parentPage, setParentPage] = useState<PostObjectItem | null>(null)
<PostObject
items={pages}
selectedItems={parentPage ? [parentPage] : []}
onChange={(items) => {
const pageItems = items as PostObjectItem[]
setParentPage(pageItems[0] || null)
}}
multiple={false}
placeholder="Select parent page..."
showFilters={["search"]}
postTypes={["page"]}
allowNull
/>Related Posts Selection
const [relatedPosts, setRelatedPosts] = useState<PostObjectItem[]>([])
<PostObject
onLoad={fetchPosts}
selectedItems={relatedPosts}
onChange={(items) => setRelatedPosts(items as PostObjectItem[])}
multiple={true}
placeholder="Select related posts..."
showFilters={["search", "post_type"]}
postTypes={["post", "tutorial", "guide"]}
sortable={true}
returnFormat="id"
/>Featured Content Selector
const [featuredContent, setFeaturedContent] = useState<PostObjectItem | null>(null)
<PostObject
items={content}
selectedItems={featuredContent ? [featuredContent] : []}
onChange={(items) => {
const contentItems = items as PostObjectItem[]
setFeaturedContent(contentItems[0] || null)
}}
placeholder="Select featured content..."
showFilters={["search", "post_type", "post_status"]}
postTypes={["post", "page", "product"]}
postStatuses={["publish"]}
showExcerpt={true}
showFeaturedImage={true}
allowNull
/>Accessibility
The Post Object component follows accessibility best practices:
- Keyboard Navigation - Full keyboard support with arrow keys and Enter
- Screen Reader Support - Proper ARIA labels and live regions
- Focus Management - Clear focus indicators and logical tab order
- High Contrast - Supports high contrast mode
- Combobox Pattern - Follows WAI-ARIA combobox guidelines
Comparison with Relationship Field
| Feature | Post Object | Relationship |
|---|---|---|
| Interface | Dropdown/Select | Dual-panel |
| Best for | Single or few selections | Multiple selections |
| Screen space | Compact | More spacious |
| Allow Null | ✅ Yes | ❌ No |
| Search | In dropdown | Separate input |
| Filtering | Optional filters | Always visible |
| Use case | Quick selection | Relationship management |