ASP.NET Core  

Creating a Comment System with Mentions (@user) and Hashtags (#tag) | Angular + Asp.Net Core

A modern collaboration or social interaction module is incomplete without a rich comment system. Applications such as Slack, GitHub, Facebook, Jira, and internal enterprise tools allow users to mention other users using the @username format and categorize or highlight topics using #hashtags.

This article explains how to build a complete mentions and hashtags–enabled comment system using Angular (frontend) and ASP.NET Core (backend) with a scalable database design in SQL Server.
The objective is to design a reusable, production-ready module suitable for enterprise web applications.

1. Key Functional Requirements

  • Users can type comments.

  • Auto-suggestions appear when typing @ for users.

  • Auto-suggestions appear when typing # for tags.

  • Comments should highlight mentions and hashtags.

  • Backend must store extracted mentions and tags.

  • Display comments with clickable mentions and hashtags.

  • Should support comment editing and deletion.

2. High-Level Workflow

User types comment →
Detect @mention or #tag →
Show suggestion list →
User selects item →
Submit comment →
Backend processes comment →
Save comment, mentions, tags →
Return formatted comment →
Display in UI

Flowchart (Comment Entry + Processing)

        +----------------------+
        | User types comment   |
        +---------+------------+
                  |
                  v
        +--------------------------+
        | Detect @ or # character |
        +------------+-------------+
                     |
          +----------+-----------+
          |                      |
          v                      v
 +-----------------+     +-----------------+
 | Load user list  |     | Load tag list   |
 +--------+--------+     +--------+--------+
          |                       |
          v                       v
 +-----------------+     +-----------------+
 | User selects    |     | User selects    |
 | mention         |     | tag             |
 +--------+--------+     +--------+--------+
          |                       |
          +-----------+-----------+
                      |
                      v
            +------------------------+
            | Submit final comment   |
            +-----------+------------+
                        |
                        v
            +--------------------------+
            | Backend extracts tokens  |
            +-----------+--------------+
                        |
                        v
            +--------------------------+
            | Save in database         |
            +-----------+--------------+
                        |
                        v
            +--------------------------+
            | Return formatted comment |
            +--------------------------+

3. ER Diagram (SQL Server)

+------------------------+
| Users                  |
+------------------------+
| UserId (PK)            |
| DisplayName            |
| Email                  |
+------------------------+

+------------------------+
| Comments               |
+------------------------+
| CommentId (PK)         |
| UserId (FK)            |
| Content                |
| CreatedOn              |
+------------------------+

+---------------------------+
| CommentMentions           |
+---------------------------+
| Id (PK)                   |
| CommentId (FK)            |
| MentionedUserId (FK)      |
+---------------------------+

+---------------------------+
| Tags                      |
+---------------------------+
| TagId (PK)                |
| TagName                   |
+---------------------------+

+---------------------------+
| CommentTags               |
+---------------------------+
| Id (PK)                   |
| CommentId (FK)            |
| TagId (FK)                |
+---------------------------+

4. Architecture Diagram (Visio Style)

               +------------------------------+
               |         Angular App          |
               +------------------------------+
                   |  Type Comment
                   v
        +--------------------------+
        |  Comment Component       |
        +------------+-------------+
                     |
                     | API Calls
                     v
        +-------------------------------+
        | ASP.NET Core API (Web API)   |
        +-------------------------------+
         | Validate | Parse | Save Data |
                     |
                     v
        +-------------------------------+
        | SQL Server (Comments, Tags)   |
        +-------------------------------+

5. Sequence Diagram

User → Angular UI: Type comment
Angular UI → SuggestionService: Detect @ or #
SuggestionService → API: Fetch matching users or tags
API → Angular: Return suggestions
User → Angular: Select mention/tag
User → Angular: Submit final comment
Angular → API: Send comment text
API → Parser: Extract @mentions and #tags
Parser → DB: Save comment, mentions, tags
DB → API: Confirm save
API → Angular: Return formatted comment
Angular → User: Show updated comment list

6. Frontend Implementation (Angular)

Detecting Mentions and Hashtags in Textbox

<textarea
  [(ngModel)]="commentText"
  (keyup)="onKeyUp($event)"
  placeholder="Write a comment...">
</textarea>

<div *ngIf="showSuggestions">
  <ul class="suggestions">
    <li *ngFor="let item of suggestions"
        (click)="selectSuggestion(item)">
      {{ item.display }}
    </li>
  </ul>
</div>

TypeScript Logic

onKeyUp(event: KeyboardEvent) {
  const text = this.commentText;
  const cursorPos = (event.target as HTMLTextAreaElement).selectionStart;

  const charBeforeCursor = text[cursorPos - 1];

  if (charBeforeCursor === '@') {
    this.loadUserSuggestions();
  }

  if (charBeforeCursor === '#') {
    this.loadTagSuggestions();
  }
}

loadUserSuggestions() {
  this.api.getUsers().subscribe(res => {
    this.showSuggestions = true;
    this.suggestions = res.map(u => ({ display: u.displayName, type: 'user', id: u.userId }));
  });
}

loadTagSuggestions() {
  this.api.getTags().subscribe(res => {
    this.showSuggestions = true;
    this.suggestions = res.map(t => ({ display: t.tagName, type: 'tag', id: t.tagId }));
  });
}

selectSuggestion(item: any) {
  const prefix = item.type === 'user' ? '@' : '#';
  this.commentText += prefix + item.display + ' ';
  this.showSuggestions = false;
}

7. Submitting the Comment

submitComment() {
  this.api.postComment({ content: this.commentText }).subscribe(() => {
    this.commentText = '';
    this.loadComments();
  });
}

8. Backend Implementation (ASP.NET Core)

Extracting Mentions and Tags

var mentions = Regex.Matches(model.Content, @"@(\w+)");
var tags = Regex.Matches(model.Content, @"#(\w+)");

API Controller

[HttpPost("comments")]
public async Task<IActionResult> PostComment(CommentDto model)
{
    var comment = new Comment
    {
        UserId = model.UserId,
        Content = model.Content,
        CreatedOn = DateTime.UtcNow
    };

    _db.Comments.Add(comment);
    await _db.SaveChangesAsync();

    // Extract mentions
    var mentions = Regex.Matches(model.Content, @"@(\w+)")
                         .Select(m => m.Groups[1].Value)
                         .ToList();

    foreach (var m in mentions)
    {
        var user = _db.Users.FirstOrDefault(u => u.DisplayName == m);
        if (user != null)
        {
            _db.CommentMentions.Add(new CommentMention
            {
                CommentId = comment.CommentId,
                MentionedUserId = user.UserId
            });
        }
    }

    // Extract hashtags
    var tags = Regex.Matches(model.Content, @"#(\w+)")
                    .Select(m => m.Groups[1].Value)
                    .ToList();

    foreach (var t in tags)
    {
        var tag = _db.Tags.FirstOrDefault(x => x.TagName == t)
                  ?? new Tag { TagName = t };

        _db.CommentTags.Add(new CommentTag
        {
            CommentId = comment.CommentId,
            TagId = tag.TagId
        });
    }

    await _db.SaveChangesAsync();

    return Ok();
}

9. Displaying Mentions and Hashtags with Highlighting

Angular Pipe

transform(value: string): string {
  value = value.replace(/@(\w+)/g, `<span class="mention">@$1</span>`);
  value = value.replace(/#(\w+)/g, `<span class="hashtag">#$1</span>`);
  return value;
}

10. UI Styling

.mention { color: #0275d8; font-weight: bold; }
.hashtag { color: #5cb85c; font-weight: bold; }
.suggestions { list-style: none; margin: 0; padding: 0; background: #f5f5f5; }
.suggestions li { padding: 6px; cursor: pointer; }

11. Best Practices

  • Use caching for user and tag suggestions to improve performance

  • Avoid over-querying the database

  • Rate-limit comment submission

  • Support soft delete for comments

  • Implement pagination for comment lists

  • Add real-time support using SignalR if needed

Conclusion

A comment system with mentions and hashtags adds professional collaboration capabilities to any web application. By using Angular for real-time processing and ASP.NET Core for strong backend parsing, you can build a scalable and reusable module. The design shown here works for enterprise portals, task management systems, social feeds, project tracking tools, LMS platforms, and more.