> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sublay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Notification Templates

> Customize the display text shown for each notification type

Sublay stores notifications as structured records with typed `metadata` — not pre-rendered strings. Your app controls how each notification type is displayed using **notification templates**.

Templates are passed to `useAppNotifications` via the `notificationTemplates` prop. Each template can define a `title` and/or `content`. Each field accepts either:

* A **string** with `$variable` placeholders that are filled from the notification's metadata, or
* A **function** that receives a typed variables object and returns a string — useful when you need full control, such as translating specific values or applying conditional logic.

## String template example

```tsx theme={null}
import { useAppNotifications } from "@sublay/react-js";

const templates = {
  entityComment: {
    title: "New comment",
    content: "$initiatorName commented on your post",
  },
  commentReply: {
    title: "New reply",
    content: "$initiatorName replied to your comment",
  },
  newFollow: {
    title: "New follower",
    content: "$initiatorName started following you",
  },
  connectionRequest: {
    title: "Connection request",
    content: "$initiatorName wants to connect",
  },
};

function NotificationFeed() {
  const { appNotifications } = useAppNotifications({ notificationTemplates: templates });

  return (
    <ul>
      {appNotifications.map((n) => (
        <li key={n.id}>
          <strong>{n.title}</strong>
          <p>{n.content}</p>
        </li>
      ))}
    </ul>
  );
}
```

## Function template example

Function templates are useful when string interpolation isn't enough — for example, when you need to translate a reaction type value into another language, or apply conditional phrasing.

```tsx theme={null}
const templates = {
  entityReaction: {
    title: ({ initiatorName, reactionType }) => {
      const reactionLabel =
        reactionType === "upvote" ? "me gusta" :
        reactionType === "heart"  ? "corazón"  : reactionType;
      return `${initiatorName} reaccionó con ${reactionLabel} a tu publicación`;
    },
  },
  commentReaction: {
    // Mix string and function in the same template
    title: ({ initiatorName, reactionType }) => {
      const reactionLabel =
        reactionType === "upvote" ? "me gusta" :
        reactionType === "heart"  ? "corazón"  : reactionType;
      return `${initiatorName} reaccionó con ${reactionLabel} a tu comentario`;
    },
    content: "$commentContent",
  },
};
```

TypeScript will infer the exact variables available for each notification type, so you get autocompletion and type safety when destructuring the parameter.

## Template keys and available variables

Each key in `notificationTemplates` corresponds to one notification type. The variables available to both string placeholders and function templates are listed below.

| Template key | Notification type | Available variables |
| - | - | - |
| `entityComment` | `entity-comment` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent`, `commentContent` |
| `commentReply` | `comment-reply` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent`, `commentContent`, `replyContent` |
| `entityMention` | `entity-mention` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent` |
| `commentMention` | `comment-mention` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent`, `commentContent` |
| `entityUpvote` | `entity-upvote` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent` |
| `commentUpvote` | `comment-upvote` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent`, `commentContent` |
| `entityReaction` | `entity-reaction` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent`, `reactionType` |
| `commentReaction` | `comment-reaction` | `initiatorName`, `initiatorUsername`, `entityTitle`, `entityContent`, `commentContent`, `reactionType` |
| `entityReactionMilestoneSpecific` | `entity-reaction-milestone-specific` | `entityTitle`, `entityContent`, `reactionType`, `milestoneCount` |
| `entityReactionMilestoneTotal` | `entity-reaction-milestone-total` | `entityTitle`, `entityContent`, `milestoneCount` |
| `commentReactionMilestoneSpecific` | `comment-reaction-milestone-specific` | `entityTitle`, `entityContent`, `commentContent`, `reactionType`, `milestoneCount` |
| `commentReactionMilestoneTotal` | `comment-reaction-milestone-total` | `entityTitle`, `entityContent`, `commentContent`, `milestoneCount` |
| `newFollow` | `new-follow` | `initiatorName`, `initiatorUsername` |
| `connectionRequest` | `connection-request` | `initiatorName`, `initiatorUsername` |
| `connectionAccepted` | `connection-accepted` | `initiatorName`, `initiatorUsername` |
| `spaceMembershipApproved` | `space-membership-approved` | `spaceName`, `spaceShortId`, `spaceSlug` |

<Note>
  All template keys are optional. If a template is not provided for a given notification type, Sublay uses a built-in default string template for that type. You only need to supply the keys you want to customize.
</Note>

## Accessing raw metadata

For building fully custom UIs, access the raw `metadata` directly on each notification. Every notification includes:

* `id` — the notification's unique ID
* `type` — the notification type string
* `isRead` — whether the user has read it
* `action` — a hint string for the action to take on tap (e.g., `"open-entity"`, `"open-comment"`, `"open-profile"`)
* `metadata` — type-specific fields (entity IDs, initiator info, etc.)
* `createdAt` — ISO timestamp


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.