X Enterprises
nuxt-x-app

Wall

Social feed components for building post walls with reactions, threaded replies, tags, and rich text input.

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

PropTypeDefaultDescription
postsArray[]Array of regular post objects.
pinnedPostsArray[]Array of pinned post objects (rendered above regular posts).
hasMoreBooleanfalseShow the load-more button.
loadingMoreBooleanfalseSet the load-more button to loading state.
loadMoreTextString'Load more posts'Label for the load-more button.
postSizeString'md'Size passed to each XAWallPost'sm', 'md', or 'lg'.
showPostActionsBooleantrueEnable the actions slot on each post.
searchableBooleanfalseShow the search input in the toolbar.
filterableBooleanfalseShow filter controls in the toolbar.
searchString''v-model search value (emits update:search).
filtersObject{}v-model filter values (emits update:filters).
filterOptionsArray[]Filter option definitions passed to the toolbar.
debounceNumber300Debounce delay in ms for search input.
searchPlaceholderString'Search posts...'Placeholder for the search field.
emptyTitleString'No posts yet'Empty state heading.
emptyDescriptionString'Posts will appear here once added.'Empty state body text.
emptyIconString'i-lucide-message-square'Empty state icon.
searchEmptyTitleString'No posts found'Search-empty state heading.
searchEmptyDescriptionString'Try adjusting your search or filters.'Search-empty state body text.

Events

EventDescription
load-moreUser clicked load more.
reactReaction toggled on a post. Payload: { post, emoji }.
replyReply toggle clicked. Payload: { post, expanded }.
reply-reactReaction toggled on a reply.
pinPin action triggered (via post-actions slot).
tag-clickA tag chip was clicked. Payload: tag object.
attachment-clickAn attachment was clicked. Payload: { post, file }.
load-repliesLoad more replies requested for a post.
update:searchSearch value changed.
update:filtersFilter values changed.
clear-filtersClear 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

PropTypeDefaultDescription
bodyStringrequiredPost body text.
timestampString | Date | NumberrequiredPost creation time.
userObjectrequiredAuthor object with name (required) and optional avatar.
attachmentsArray[]File attachment objects: { name, size, type?, url? }.
tagsArray[]Tag objects: { label, color? }.
reactionsArray[]Reaction objects: { emoji, count, reacted }.
replyCountNumber0Number of replies (controls reply toggle visibility).
pinnedBooleanfalseRenders a pinned indicator banner at the top.
sizeString'md'Post size variant — 'sm', 'md', or 'lg'.
showActionsBooleantrueEnable the #actions slot area.
showReplyButtonBooleantrueShow reply button even when replyCount is 0.

Events

EventDescription
reactReaction toggled. Payload: { emoji, ... }.
replyReply toggle button clicked.
tag-clickA tag was clicked. Payload: tag object.
attachment-clickAn 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

PropTypeDefaultDescription
modelValueString''v-model for the textarea content.
placeholderString'Write a post...'Textarea placeholder.
allowAttachmentsBooleantrueShow file upload button.
allowTagsBooleantrueShow the tag selector.
availableTagsArray[]Tag suggestions for the picker.
maxTagsNumber5Maximum tags allowed on a post.
acceptString'*'Accepted file MIME types for the file picker.
maxFileSizeNumber262144000Maximum file size in bytes (default 250 MB).
maxFilesNumber5Maximum number of file attachments.
loadingBooleanfalsePuts the submit button in loading state.
disabledBooleanfalseDisables the entire input.
submitTextString'Post'Submit button label.
userObjectnullCurrent user { name, avatar? } for avatar display in header.
minRowsNumber2Minimum textarea rows.
maxRowsNumber6Maximum auto-grow rows.

Events

EventPayloadDescription
update:modelValueStringTextarea content changed.
submit{ body, files, tags }User submitted the post.
file-errorerror objectFile 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

PropTypeDefaultDescription
repliesArray[]Array of reply post objects.
expandedBooleanfalseControls visibility via v-model.
maxVisibleNumber3Number of replies shown before a "show more" button appears.
loadingBooleanfalseShows a spinner inside the section.
totalCountNumbernullTotal reply count for computing "show N more" (falls back to replies.length).

Events

EventDescription
update:expandedCollapse/expand state changed.
load-moreUser clicked "Show N more replies".
reactReaction toggled on a reply.
tag-clickTag clicked on a reply.
attachment-clickAttachment 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

PropTypeDefaultDescription
reactionsArray[]Current reactions: { emoji, count, reacted }.
availableReactionsArray['👍', '❤️', '😄', '😮', '😢', '🎉']Emoji options shown in the picker popover.
readonlyBooleanfalseDisables all interaction and hides the picker.

Events

EventPayloadDescription
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

PropTypeDefaultDescription
tagsArray[]Active tag objects: { label, color? }.
readonlyBooleanfalseDisplay only — hides add/remove controls.
availableTagsArray[]Tag suggestions for the add dropdown.
maxTagsNumber5Maximum number of tags. Hides the add button when reached.

Events

EventPayloadDescription
update:tagsArrayEmitted when tags are added or removed.
tag-clicktag objectEmitted 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.
Copyright © 2026