Chức năng mention đã trở thành tiêu chuẩn trong hầu hết các ứng dụng hiện đại như Facebook, Twitter, Slack, Notion hay GitHub. Việc gõ ký tự @ và gợi ý danh sách người dùng giúp trải nghiệm tương tác trở nên trực quan hơn, đồng thời hỗ trợ luồng trao đổi trong nhóm hiệu quả hơn.

Nếu bạn đang xây dựng một ứng dụng có phần bình luận, chat, hoặc soạn thảo nội dung cộng tác, việc hỗ trợ mention là điều gần như bắt buộc. Bài viết này sẽ phân tích cách xây dựng chức năng mention từ A đến Z, bao gồm kiến trúc, UI, logic lọc gợi ý và cách lưu dữ liệu.

1. Mention hoạt động như thế nào?

Một hệ thống mention hoàn chỉnh thường có những đặc điểm sau:

  • Khi người dùng gõ @, hệ thống bật lên một popup gợi ý danh sách user.

  • Khi tiếp tục gõ ký tự sau @, danh sách gợi ý được lọc theo tên.

  • Khi chọn một user, text sẽ được thay bằng mention dạng “@Tên Người Dùng”.

  • Hệ thống lưu lại ID người được mention, không chỉ lưu text.

  • Khi render, giao diện hiển thị mention theo style riêng, có màu và hover.

Để làm được điều này, chúng ta sẽ tách thành 3 phần: UI, logic xử lý text, và backend.

2. Xây dựng UI mention

Có 2 hướng triển khai UI phổ biến:

Cách 1: Tự xây dựng từ đầu bằng textarea + popup

Dùng một textarea hoặc contentEditable, khi phát hiện ký tự @ trong text thì hiển thị popup suggestion ngay dưới vị trí caret.

Thách thức:

  • Tính toán vị trí caret trong textarea hoặc contentEditable.

  • Tách text để biết từ hiện tại đang nhập là gì.

  • Kiểm soát hành vi khi người dùng nhấn Enter, Tab, hoặc click chọn.

Ưu điểm:

  • Tùy biến cao.

  • Không phụ thuộc thư viện.

Cách 2: Dùng editor có hỗ trợ mention sẵn

Nếu bạn dùng React, có thể chọn:

  • TipTap

  • Slate.js

  • DraftJS

  • QuillJS

Các editor này có extension mention, giúp bạn xử lý:

  • Gợi ý tự động.

  • Styling tên người được mention.

  • Lưu và parse node mention thay vì text thường.

Ưu điểm:

  • Giảm công sức xử lý text phức tạp.

  • Tối ưu cho các editor nâng cao.

3. Logic phát hiện mention trong text

Khi người dùng gõ vào editor, bạn cần:

  1. Lấy từ hiện tại (the current word) bằng cách:

    • Lấy vị trí caret.

    • Quét ngược đến khi gặp khoảng trắng hoặc ký tự đặc biệt.

  2. Kiểm tra nếu từ bắt đầu bằng @.

  3. Nếu đúng, bật gợi ý danh sách user.

Ví dụ từ hiện tại là:

@jo

Khi đó bạn gửi request API để lấy danh sách user có tên bắt đầu bằng “jo”.

Bạn nên debounce API để tránh spam API liên tục khi người dùng gõ.

4. Dữ liệu và API Suggest User

Endpoint mẫu:

GET /api/users/search?keyword=jo

API nên trả về:

[
  { "id": 1, "name": "John Doe", "avatar": "/john.png" },
  { "id": 2, "name": "Jonas Le" }
]

Tại giao diện suggestion:

  • Hiển thị avatar.

  • Hiển thị tên đầy đủ.

  • Sử dụng phím mũi tên lên xuống để điều hướng.

  • Nhấn Enter để chọn.

5. Chèn mention vào text (insert mention)

Sau khi người dùng chọn một user, bạn cần thay thế từ “@jo” bằng một node mention.

Nếu bạn dùng editor tự custom:

  • Thay text “@jo” bằng “@John Doe”

  • Gán thêm metadata như:

<span data-user-id="1" class="mention">@John Doe</span>
  • Cập nhật caret ở sau mention.

Nếu bạn dùng editor như TipTap:

  • Dùng command insertContent hoặc extension mention đã có sẵn.

  • Hệ thống tự tạo node mention.

6. Lưu dữ liệu mention trong database

Để hiển thị lại mention đúng màu, đúng user, không bị sai khi user đổi tên, bạn tuyệt đối không nên chỉ lưu text.

Cách tốt nhất

  • Lưu nội dung dưới dạng JSON hoặc dữ liệu rich text (ví dụ TipTap JSON).

  • Trong đó mỗi mention node lưu:

{
  type: "mention",
  attrs: {
    id: 1,
    label: "John Doe"
  }
}
  • Khi render lại nội dung, client tự style mention theo thiết kế của bạn.

Lưu thêm bảng mention

Nếu muốn thống kê hoặc thông báo:

  • Tạo bảng post_mentions hoặc comment_mentions.

id | post_id | user_id

Khi user A mention user B, bạn lưu record này để gửi thông báo.

7. Render lại nội dung mention

Khi bạn lấy dữ liệu từ DB:

  • Parse JSON.

  • Render node mention thành:

<a href="/user/1" class="mention">@John Doe</a>
  • Style đẹp:

.mention {
  color: #2563eb;
  background: #eef4ff;
  padding: 2px 4px;
  border-radius: 4px;
  cursor: pointer;
}

8. Những vấn đề cần lưu ý

  • Xử lý mention trong mobile sẽ khó hơn, cần tối ưu UI.

  • Nếu dùng textarea thuần, việc tính caret rất phức tạp.

  • Nếu user đổi tên, bạn nên hiển thị tên mới nhưng link id cũ.

  • Không nên để API trả quá nhiều user, giới hạn 10 kết quả gợi ý.

  • Hãy giải quyết xung đột khi người dùng xóa một mention node.

9. Kết luận

Chức năng mention là một phần nhỏ nhưng quan trọng trong các ứng dụng có tính tương tác cao. Việc xây dựng từ đầu không quá khó, nhưng để mượt mà, tự nhiên và chính xác thì bạn cần xử lý cả giao diện, logic text, API và cách lưu trữ.

Nếu bạn đang xây dựng hệ thống chat, bình luận, hay công cụ soạn thảo nội dung, hãy bắt đầu bằng việc chọn loại editor phù hợp và thiết kế rõ format lưu trữ nội dung ngay từ đầu. Điều này sẽ giúp bạn mở rộng hệ thống dễ dàng hơn trong tương lai.