Wall
Wall
The Wall category provides a complete social feed system. XAWallFeed is the top-level orchestrator; it renders pinned and regular post lists, delegates search/filter to a toolbar, and shows appropriate empty or loading states. Individual posts are rendered by XAWallPost. The remaining components — XAWallInput, XAWallReplies, XAWallReactions, and XAWallTags — can be composed independently or are automatically used inside XAWallFeed and XAWallPost.
Components
<XAWallFeed />
The main feed container. It separates pinned posts (rendered with a highlighted border) from regular posts, wires up search and filter toolbars, handles reply expansion state, and delegates load-more pagination. When no posts exist it shows XAStateEmpty; during a search with no results it shows a search-empty state.
<XAWallFeed
:posts="posts"
:pinned-posts="pinnedPosts"
:has-more="hasMorePages"
:loading-more="loading"
searchable
filterable
:filter-options="filterOptions"
@load-more="fetchNextPage"
@react="handleReaction"
@reply="handleReply"
@tag-click="filterByTag"
>
<template #input>
<XAWallInput v-model="newPost" @submit="createPost" />
</template>
<template #post-actions="{ post }">
<UButton size="xs" icon="i-lucide-pin" variant="ghost" @click="pin(post)" />
</template>
</XAWallFeed>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
posts | Array | [] | Array of regular post objects. |
pinnedPosts | Array | [] | Array of pinned post objects (rendered above regular posts). |
hasMore | Boolean | false | Show the load-more button. |
loadingMore | Boolean | false | Set the load-more button to loading state. |
loadMoreText | String | 'Load more posts' | Label for the load-more button. |
postSize | String | 'md' | Size passed to each XAWallPost — 'sm', 'md', or 'lg'. |
showPostActions | Boolean | true | Enable the actions slot on each post. |
searchable | Boolean | false | Show the search input in the toolbar. |
filterable | Boolean | false | Show filter controls in the toolbar. |
search | String | '' | v-model search value (emits update:search). |
filters | Object | {} | v-model filter values (emits update:filters). |
filterOptions | Array | [] | Filter option definitions passed to the toolbar. |
debounce | Number | 300 | Debounce delay in ms for search input. |
searchPlaceholder | String | 'Search posts...' | Placeholder for the search field. |
emptyTitle | String | 'No posts yet' | Empty state heading. |
emptyDescription | String | 'Posts will appear here once added.' | Empty state body text. |
emptyIcon | String | 'i-lucide-message-square' | Empty state icon. |
searchEmptyTitle | String | 'No posts found' | Search-empty state heading. |
searchEmptyDescription | String | 'Try adjusting your search or filters.' | Search-empty state body text. |
Events
| Event | Description |
|---|---|
load-more | User clicked load more. |
react | Reaction toggled on a post. Payload: { post, emoji }. |
reply | Reply toggle clicked. Payload: { post, expanded }. |
reply-react | Reaction toggled on a reply. |
pin | Pin action triggered (via post-actions slot). |
tag-click | A tag chip was clicked. Payload: tag object. |
attachment-click | An attachment was clicked. Payload: { post, file }. |
load-replies | Load more replies requested for a post. |
update:search | Search value changed. |
update:filters | Filter values changed. |
clear-filters | Clear filters button clicked. |
<XAWallPost />
The individual post card. Renders the author avatar with initials fallback, relative and absolute timestamps, tags, body text, file attachments, emoji reactions via XAWallReactions, and a reply toggle. An optional #actions slot renders a dropdown for post-level controls. A #replies slot receives the expandable reply section (typically XAWallReplies).
<XAWallPost
body="Hello team! Check out this update."
:timestamp="post.createdAt"
:user="{ name: 'Jane Smith', avatar: '/avatars/jane.jpg' }"
:reactions="post.reactions"
:tags="post.tags"
:reply-count="post.replyCount"
size="md"
@react="handleReact"
@reply="toggleReplies"
>
<template #replies>
<XAWallReplies :replies="post.replies" :expanded="repliesOpen" />
</template>
</XAWallPost>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
body | String | required | Post body text. |
timestamp | String | Date | Number | required | Post creation time. |
user | Object | required | Author object with name (required) and optional avatar. |
attachments | Array | [] | File attachment objects: { name, size, type?, url? }. |
tags | Array | [] | Tag objects: { label, color? }. |
reactions | Array | [] | Reaction objects: { emoji, count, reacted }. |
replyCount | Number | 0 | Number of replies (controls reply toggle visibility). |
pinned | Boolean | false | Renders a pinned indicator banner at the top. |
size | String | 'md' | Post size variant — 'sm', 'md', or 'lg'. |
showActions | Boolean | true | Enable the #actions slot area. |
showReplyButton | Boolean | true | Show reply button even when replyCount is 0. |
Events
| Event | Description |
|---|---|
react | Reaction toggled. Payload: { emoji, ... }. |
reply | Reply toggle button clicked. |
tag-click | A tag was clicked. Payload: tag object. |
attachment-click | An attachment row was clicked. Payload: file object. |
<XAWallInput />
A post composer component. Provides an auto-resizing textarea (with Cmd/Ctrl+Enter submit), optional file attachment upload, optional tag selection via XAWallTags, and a footer with a submit button. Displays the current user's avatar when user is provided.
<XAWallInput
v-model="postBody"
placeholder="What's on your mind?"
:user="currentUser"
:allow-attachments="true"
:allow-tags="true"
:available-tags="availableTags"
:loading="submitting"
submit-text="Post"
@submit="({ body, files, tags }) => createPost(body, files, tags)"
/>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | String | '' | v-model for the textarea content. |
placeholder | String | 'Write a post...' | Textarea placeholder. |
allowAttachments | Boolean | true | Show file upload button. |
allowTags | Boolean | true | Show the tag selector. |
availableTags | Array | [] | Tag suggestions for the picker. |
maxTags | Number | 5 | Maximum tags allowed on a post. |
accept | String | '*' | Accepted file MIME types for the file picker. |
maxFileSize | Number | 262144000 | Maximum file size in bytes (default 250 MB). |
maxFiles | Number | 5 | Maximum number of file attachments. |
loading | Boolean | false | Puts the submit button in loading state. |
disabled | Boolean | false | Disables the entire input. |
submitText | String | 'Post' | Submit button label. |
user | Object | null | Current user { name, avatar? } for avatar display in header. |
minRows | Number | 2 | Minimum textarea rows. |
maxRows | Number | 6 | Maximum auto-grow rows. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue | String | Textarea content changed. |
submit | { body, files, tags } | User submitted the post. |
file-error | error object | File validation failed (size/type). |
<XAWallReplies />
An animated, expandable reply thread. Renders up to maxVisible replies using XAWallPost at size="sm", shows a "Show N more" button when there are additional replies, and emits load-more for server-side pagination. Accepts a #input slot for the reply composer and a #reply-actions scoped slot for per-reply controls.
<XAWallReplies
:replies="post.replies"
:expanded="isExpanded"
:total-count="post.replyCount"
:max-visible="3"
@update:expanded="isExpanded = $event"
@load-more="loadMoreReplies"
@react="handleReplyReaction"
>
<template #input>
<XAWallInput v-model="replyBody" submit-text="Reply" @submit="submitReply" />
</template>
</XAWallReplies>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
replies | Array | [] | Array of reply post objects. |
expanded | Boolean | false | Controls visibility via v-model. |
maxVisible | Number | 3 | Number of replies shown before a "show more" button appears. |
loading | Boolean | false | Shows a spinner inside the section. |
totalCount | Number | null | Total reply count for computing "show N more" (falls back to replies.length). |
Events
| Event | Description |
|---|---|
update:expanded | Collapse/expand state changed. |
load-more | User clicked "Show N more replies". |
react | Reaction toggled on a reply. |
tag-click | Tag clicked on a reply. |
attachment-click | Attachment clicked on a reply. |
<XAWallReactions />
An emoji reaction bar. Displays active reactions (count > 0) as pill buttons that toggle the current user's reaction. A hover popover provides a set of emoji picker buttons for adding new reactions. Emits a single react event with the emoji.
<XAWallReactions
:reactions="[
{ emoji: '👍', count: 3, reacted: true },
{ emoji: '❤️', count: 1, reacted: false }
]"
:available-reactions="['👍', '❤️', '😄', '🎉']"
@react="({ emoji }) => toggleReaction(post, emoji)"
/>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
reactions | Array | [] | Current reactions: { emoji, count, reacted }. |
availableReactions | Array | ['👍', '❤️', '😄', '😮', '😢', '🎉'] | Emoji options shown in the picker popover. |
readonly | Boolean | false | Disables all interaction and hides the picker. |
Events
| Event | Payload | Description |
|---|---|---|
react | { emoji } | Emitted when an emoji is toggled or added. |
<XAWallTags />
A tag chip list with optional add/remove controls. In edit mode, existing tags show an × button to remove them and a dropdown button lets users pick from availableTags. In readonly mode only the chips are shown, each emitting tag-click when clicked.
<!-- Editable -->
<XAWallTags
:tags="selectedTags"
:available-tags="allTags"
:max-tags="3"
@update:tags="selectedTags = $event"
@tag-click="filterByTag"
/>
<!-- Read-only display -->
<XAWallTags :tags="post.tags" readonly @tag-click="filterByTag" />
Props
| Prop | Type | Default | Description |
|---|---|---|---|
tags | Array | [] | Active tag objects: { label, color? }. |
readonly | Boolean | false | Display only — hides add/remove controls. |
availableTags | Array | [] | Tag suggestions for the add dropdown. |
maxTags | Number | 5 | Maximum number of tags. Hides the add button when reached. |
Events
| Event | Payload | Description |
|---|---|---|
update:tags | Array | Emitted when tags are added or removed. |
tag-click | tag object | Emitted when any tag chip is clicked. |
AI Context
category: Wall
package: "@xenterprises/nuxt-x-app"
use-when: >
Use XAWallFeed as the top-level container when building a social/activity feed.
Pass posts and pinnedPosts arrays; it handles layout, search, filters, empty states,
and reply expansion automatically. Use XAWallPost standalone when you need a single
post card outside a feed context. Use XAWallInput to compose new posts or replies —
it manages file attachments and tag selection internally. Use XAWallReplies to add
threaded reply expansion to any XAWallPost. Use XAWallReactions and XAWallTags as
standalone primitives when embedding reaction bars or tag chips in custom layouts.
