npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@libs-ui/pipes-format-text-highlight-by-keyword

v0.2.357-11

Published

> Pipe tô màu (highlight) từ khóa trong chuỗi văn bản, hỗ trợ tìm kiếm không dấu tiếng Việt và tùy chỉnh CSS class.

Readme

@libs-ui/pipes-format-text-highlight-by-keyword

Pipe tô màu (highlight) từ khóa trong chuỗi văn bản, hỗ trợ tìm kiếm không dấu tiếng Việt và tùy chỉnh CSS class.

Giới thiệu

LibsUiPipesFormatTextHighlightByKeywordPipe là một Angular Pipe bọc quanh hàm tiện ích highlightByKeyword từ @libs-ui/utils. Pipe nhận vào một chuỗi văn bản và một từ khóa, trả về chuỗi HTML với các đoạn khớp từ khóa được bọc trong thẻ <span> kèm CSS class tô màu. Pipe hỗ trợ tìm kiếm không phân biệt dấu tiếng Việt (gõ "an" có thể match "An", "ăn", "ân", "ản"...) và không phân biệt hoa/thường.

Tính năng

  • ✅ Highlight tất cả các lần xuất hiện của từ khóa trong chuỗi
  • ✅ Tìm kiếm không dấu — "an" match "An", "ăn", "ân", "ản"... (hỗ trợ tiếng Việt đầy đủ)
  • ✅ Không phân biệt hoa/thường (case-insensitive)
  • ✅ Tùy chỉnh CSS class cho phần highlight qua tham số classHightLight
  • ✅ Tham số ignoreHighlight để bật/tắt highlight linh hoạt mà không cần @if trong template
  • ✅ Xử lý an toàn khi value hoặc searchnull/undefined
  • ✅ Standalone pipe, dùng được ngay không cần NgModule

Khi nào sử dụng

  • Highlight keyword trong danh sách kết quả tìm kiếm (search result page)
  • Tô màu từ khóa trong dropdown autocomplete khi người dùng gõ
  • Highlight từ khóa trong bảng dữ liệu khi lọc/filter
  • Hiển thị đoạn văn preview của search engine nội bộ với keyword được tô màu
  • Cần tìm kiếm không phân biệt dấu tiếng Việt (gõ "an" → highlight "An", "Ân", "ăn")

Cài đặt

npm install @libs-ui/pipes-format-text-highlight-by-keyword

Import

import { LibsUiPipesFormatTextHighlightByKeywordPipe } from '@libs-ui/pipes-format-text-highlight-by-keyword';

@Component({
  standalone: true,
  imports: [LibsUiPipesFormatTextHighlightByKeywordPipe],
})
export class ExampleComponent {}

Ví dụ sử dụng

1. Highlight cơ bản

import { Component, signal } from '@angular/core';
import { LibsUiPipesFormatTextHighlightByKeywordPipe } from '@libs-ui/pipes-format-text-highlight-by-keyword';

@Component({
  standalone: true,
  imports: [LibsUiPipesFormatTextHighlightByKeywordPipe],
  template: `
    <!-- ✅ BẮT BUỘC dùng [innerHTML] — pipe trả về HTML string -->
    <p [innerHTML]="text | LibsUiPipesFormatTextHighlightByKeywordPipe : keyword"></p>

    <!-- ❌ KHÔNG dùng {{ }} — sẽ hiện HTML string thô, không render -->
    <!-- <p>{{ text | LibsUiPipesFormatTextHighlightByKeywordPipe : keyword }}</p> -->
  `,
})
export class SearchResultComponent {
  protected text = signal('Angular is a powerful framework for building web applications');
  protected keyword = signal('angular');
}

Output HTML được tạo ra:

<span class="bg-[#19344a] text-white">Angular</span> is a powerful framework for building web applications

2. Tìm kiếm không dấu tiếng Việt

import { Component, signal } from '@angular/core';
import { LibsUiPipesFormatTextHighlightByKeywordPipe } from '@libs-ui/pipes-format-text-highlight-by-keyword';

@Component({
  standalone: true,
  imports: [LibsUiPipesFormatTextHighlightByKeywordPipe],
  template: `
    <!-- Gõ "an" (không dấu) → highlight "An", "ăn", "ân", "ản"... trong text có dấu -->
    <p [innerHTML]="name | LibsUiPipesFormatTextHighlightByKeywordPipe : searchTerm"></p>
  `,
})
export class VietnameseSearchComponent {
  protected name = signal('Nguyễn Văn An là kỹ sư phần mềm tài năng tại Hà Nội');
  protected searchTerm = signal('an');
  // "an" (không dấu) sẽ match: "An", "ăn" (tài năng), v.v.
}

3. Custom CSS class cho phần highlight

import { Component, signal } from '@angular/core';
import { LibsUiPipesFormatTextHighlightByKeywordPipe } from '@libs-ui/pipes-format-text-highlight-by-keyword';

@Component({
  standalone: true,
  imports: [LibsUiPipesFormatTextHighlightByKeywordPipe],
  template: `
    <!-- Highlight màu vàng thay vì mặc định dark navy -->
    <p
      [innerHTML]="text | LibsUiPipesFormatTextHighlightByKeywordPipe
        : keyword
        : false
        : 'bg-yellow-300 text-gray-900 font-bold'">
    </p>
  `,
})
export class CustomHighlightComponent {
  protected text = signal('Tìm kiếm nhanh với highlight màu tùy chỉnh theo thiết kế');
  protected keyword = signal('highlight');
}

4. Toggle highlight theo trạng thái tìm kiếm

import { Component, signal } from '@angular/core';
import { LibsUiPipesFormatTextHighlightByKeywordPipe } from '@libs-ui/pipes-format-text-highlight-by-keyword';

@Component({
  standalone: true,
  imports: [LibsUiPipesFormatTextHighlightByKeywordPipe],
  template: `
    <!-- Chỉ highlight khi isSearching = true — không cần @if trong template -->
    <p
      [innerHTML]="text | LibsUiPipesFormatTextHighlightByKeywordPipe
        : keyword
        : !isSearching()">
    </p>
    <button (click)="handlerToggleSearch($event)">
      {{ isSearching() ? 'Tắt highlight' : 'Bật highlight' }}
    </button>
  `,
})
export class ToggleHighlightComponent {
  protected text = signal('Text sẽ được highlight khi đang trong chế độ tìm kiếm');
  protected keyword = signal('highlight');
  protected isSearching = signal(false);

  protected handlerToggleSearch(event: Event): void {
    event.stopPropagation();
    this.isSearching.update(v => !v);
  }
}

5. Dùng trong TypeScript (không qua pipe)

Pipe là thin wrapper của hàm highlightByKeyword trong @libs-ui/utils. Khi cần gọi trong TypeScript, import thẳng hàm đó — không cần inject pipe:

import { highlightByKeyword } from '@libs-ui/utils';

// Highlight cơ bản
const result = highlightByKeyword('Nguyễn Văn An', 'an');
// Output: 'Nguyễn Văn <span class="bg-[#19344a] text-white">An</span>'

// Custom class
const customResult = highlightByKeyword(
  'Hello World từ Việt Nam',
  'hello',
  false,
  'bg-yellow-300 text-gray-900 font-bold'
);
// Output: '<span class="bg-yellow-300 text-gray-900 font-bold">Hello</span> World từ Việt Nam'

// Tắt highlight
const plain = highlightByKeyword('Text bình thường', 'text', true);
// Output: 'Text bình thường' (giữ nguyên, không bọc span)

// Trong component — dùng để gán vào property hiển thị qua [innerHTML]
@Component({
  standalone: true,
  template: `<p [innerHTML]="highlightedHtml"></p>`,
})
export class MyComponent {
  highlightedHtml = highlightByKeyword('Kết quả tìm kiếm phần mềm', 'phần mềm');
}

6. Dùng trực tiếp pipe.transform() (standalone)

import { LibsUiPipesFormatTextHighlightByKeywordPipe } from '@libs-ui/pipes-format-text-highlight-by-keyword';

const pipe = new LibsUiPipesFormatTextHighlightByKeywordPipe();

// Cú pháp: pipe.transform(value, search, ignoreHighlight?, classHightLight?)
const result1 = pipe.transform('Angular framework', 'angular');
// → '<span class="bg-[#19344a] text-white">Angular</span> framework'

const result2 = pipe.transform('Dữ liệu tiếng Việt', 'du lieu', false, 'bg-blue-200');
// → tìm "du lieu" không dấu → match "Dữ liệu" → bọc span với bg-blue-200

const result3 = pipe.transform(undefined, 'keyword');
// → '__' (CHARACTER_DATA_EMPTY — an toàn với undefined, KHÔNG phải chuỗi rỗng)

const result4 = pipe.transform('Text đầy đủ', 'keyword', true);
// → 'Text đầy đủ' (ignoreHighlight = true → trả về nguyên bản)

Transform (Pipe)

Cú pháp template

value | LibsUiPipesFormatTextHighlightByKeywordPipe : search : ignoreHighlight? : classHightLight?

Bảng tham số

| Tham số | Type | Bắt buộc | Default | Mô tả | Ví dụ | |---|---|---|---|---|---| | value | string \| undefined | ✅ | — | Chuỗi văn bản gốc cần tô màu keyword | 'Nguyễn Văn An' | | search | string \| undefined | ✅ | — | Từ khóa cần highlight trong chuỗi | 'an' | | ignoreHighlight | boolean \| undefined | ❌ | undefined | Nếu true, bỏ qua highlight và trả về value gốc không đổi | true / !isSearching() | | classHightLight | string \| undefined | ❌ | 'bg-[#19344a] text-white' | CSS class áp dụng cho <span> bao quanh keyword. Có thể dùng Tailwind hoặc custom CSS class | 'bg-yellow-300 text-gray-900 font-bold' |

Giá trị trả về

Pipe trả về string — là HTML string chứa các thẻ <span> bao quanh keyword:

<!-- Ví dụ output khi search = 'angular' -->
<span class="bg-[#19344a] text-white">Angular</span> is a powerful framework

BẮT BUỘC bind qua [innerHTML] để Angular render HTML thay vì hiển thị text thô.

Logic ẩn quan trọng

Tìm kiếm không dấu (deleteUnicode)

Pipe sử dụng hàm deleteUnicode() nội bộ để chuyển cả valuesearch về dạng không dấu trước khi so sánh vị trí match. Sau đó lấy substring tương ứng trong value gốc (có dấu) để highlight đúng ký tự.

search = 'an'
→ searchConvert = 'an'
→ valueConvert  = 'nguyen van an la ky su tai nang'
→ tìm vị trí 'an' trong valueConvert
→ highlight đúng substring có dấu tương ứng trong value gốc

Kết quả: "Nguyễn Văn An là kỹ sư tài năng" (cả "An" và "ăn" trong "năng" đều được highlight).

Thứ tự xử lý và early return

  1. Nếu value là falsy → trả về hằng số CHARACTER_DATA_EMPTY (giá trị thực tế là chuỗi '__', KHÔNG phải chuỗi rỗng '')
  2. Nếu search trống hoặc ignoreHighlight = true → trả về value gốc nguyên vẹn
  3. Nếu không có match nào → trả về value gốc nguyên vẹn
  4. Mọi exception được bắt và log — pipe không bao giờ throw lỗi ra ngoài

Lưu ý quan trọng

⚠️ Bắt buộc dùng [innerHTML]: Pipe trả về HTML string chứa <span> tags. Nếu dùng {{ }} trong template, Angular sẽ escape HTML và hiển thị text thô như <span class="...">keyword</span> thay vì render màu.

⚠️ Bảo mật XSS: Chỉ dùng với dữ liệu đã tin cậy (từ API đã sanitize hoặc dữ liệu nội bộ). Nếu value đến từ user input chưa kiểm tra, hãy sanitize trước khi truyền vào pipe. Không truyền nội dung HTML động chưa qua escapeHtml() / xssFilter().

⚠️ Tên tham số classHightLight: Lưu ý cách viết — chỉ có 1 chữ "l" trong "HightLight" (không phải "Highlight"). Đây là tên tham số trong API hiện tại.

⚠️ Nhiều lần xuất hiện: Pipe highlight TẤT CẢ các lần xuất hiện của keyword trong chuỗi, không chỉ lần đầu tiên.

⚠️ Dùng ignoreHighlight thay @if: Thay vì dùng @if để chọn giữa 2 template (có/không highlight), hãy dùng tham số ignoreHighlight — gọn hơn và không tạo/hủy DOM node.

⚠️ value falsy trả về '__', không phải chuỗi rỗng: Khi valuenull/undefined/'', pipe trả về literal '__' (hằng số CHARACTER_DATA_EMPTY) thay vì ''. Nếu hiển thị trực tiếp, UI sẽ thấy __ — cần tự xử lý fallback (vd: @if (value)) trước khi truyền vào pipe nếu không muốn hiển thị __.