Discussion

Threaded discussion / commenting component. Two-level threading (top-level posts and replies), four sort modes, cursor-based pagination, reactions, post reporting, and authentication-aware UI.

Import

import { Discussion } from "fansunited-frontend-components";
import { DiscussionProps, DiscussionSortType } from "fansunited-frontend-core";

Required props

PropTypeDescription
entityIdstringUnique discussion identifier (e.g. article ID, match ID).
sdkFansUnitedSDKModelSDK instance.
languageLanguageTypeDisplay language.

Discussion does not take a template prop — its layout is always a single threaded list that adapts to the container width.

Optional props

PropTypeDefaultDescription
themeOptionsCustomThemeOptionsSee Theming.
discussionLabelstringTitle used when the discussion is created for the first time.
discussionUrlstringURL associated with the discussion content (used in shares/back-references).
defaultSortDiscussionSortType"LATEST"Initial sort order.
postsPerPagenumber20Posts loaded per page.
showReactionsbooleantrueShow reaction buttons.
showRepliesbooleantrueEnable reply functionality.
showReportPostbooleantrueShow the report option in the post menu.
showModeratedPostsbooleanfalseDisplay moderated posts with a masked design (content replaced by the moderation reason).
infiniteScrollbooleanfalseLoad more posts on scroll instead of showing a "Load More" button.
userIsLoggedInbooleanfalseWhether the current user is authenticated.
onSignInClick() => voidCallback when the sign-in prompt is clicked.

Note: Discussion uses a simpler onSignInClick callback, not the full SignInCTADetails object.

Sort modes

type DiscussionSortType = "LATEST" | "OLDEST" | "POPULAR" | "INTERACTED";
ValueOrder
LATESTNewest first (default).
OLDESTOldest first.
POPULARMost-reacted first.
INTERACTEDMost-replied first.

Authentication and sign-in

When userIsLoggedIn={false}:

  • The post composer is replaced with a sign-in prompt.
  • Reactions, replies, delete, and report actions are gated behind authentication.
  • Passing onSignInClick makes the sign-in button active; omitting it shows a disabled button.
<Discussion
  {...otherProps}
  userIsLoggedIn={false}
  onSignInClick={() => openSignInModal()}
/>

Reactions

Eight reaction types are available when showReactions={true}:

type ReactionType = "LIKE" | "DISLIKE" | "LOVE" | "LAUGH" | "CARE" | "WOW" | "SAD" | "ANGRY";
  • Click an emoji to toggle the reaction.
  • Click the same emoji again to remove it.
  • Only authenticated users can react.

Moderated posts

showModeratedPosts={true} fetches and displays moderated comments with a masked design. The original content is replaced by the moderation reason (or a localised fallback), while avatar, username, timestamp, reactions, and reply button remain visible.

Examples

Basic

<Discussion
  entityId="article-123"
  sdk={sdk}
  language="en"
  discussionLabel="Liverpool vs Man City — Match Reaction"
/>

Authenticated user, full features

<Discussion
  entityId="article-123"
  sdk={sdk}
  language="en"
  discussionLabel="Liverpool vs Man City — Match Reaction"
  discussionUrl="https://your-site.com/articles/liverpool-vs-man-city"
  userIsLoggedIn={true}
  defaultSort="POPULAR"
  postsPerPage={10}
  showReactions
  showReplies
  showReportPost
  themeOptions={{ mode: "light" }}
/>

Minimal read-only style

<Discussion
  entityId="article-123"
  sdk={sdk}
  language="en"
  discussionLabel="Post Comments"
  userIsLoggedIn={false}
  showReactions={false}
  showReplies={false}
  showReportPost={false}
  onSignInClick={() => openSignInModal()}
/>

Dark theme with sign-in integration

<Discussion
  entityId="match-456"
  sdk={sdk}
  language="en"
  discussionLabel="Match Day Chat"
  userIsLoggedIn={isUserLoggedIn}
  onSignInClick={() => router.push("/login")}
  defaultSort="LATEST"
  postsPerPage={20}
  themeOptions={{
    mode: "dark",
    colorSchemes: {
      dark: {
        surface: "#212121",
        textPrimary: "#FAFAFA",
        palette: {
          primary: {
            plainColor: "#2397F3",
            primaryContainer: "#1A77D2",
            onPrimary: "#FFFFFF",
          },
        },
      },
    },
  }}
/>