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/components-line-clamp

v0.2.357-11

Published

> Component giới hạn số dòng văn bản, hỗ trợ nút Xem thêm / Thu gọn và Tooltip tích hợp sẵn.

Readme

@libs-ui/components-line-clamp

Component giới hạn số dòng văn bản, hỗ trợ nút Xem thêm / Thu gọn và Tooltip tích hợp sẵn.

Giới thiệu

@libs-ui/components-line-clamp là component Angular dùng để cắt ngắn đoạn văn bản dài theo chiều cao tối đa (px) và tự động hiển thị nút điều khiển "Xem thêm" / "Thu gọn" khi nội dung vượt giới hạn. Component hỗ trợ render cả HTML (có lọc XSS) lẫn plain text, tích hợp Tooltip khi hover, hiệu ứng gradient mờ dần, và cung cấp FunctionsControl để component cha điều khiển trực tiếp qua ViewChild.

Tính năng

  • Giới hạn chiều cao hiển thị dựa trên maxHeight (px) — tính toán thực tế từ DOM
  • Tự động hiển thị / ẩn nút "Xem thêm" và "Thu gọn" khi nội dung thay đổi
  • Hỗ trợ render HTML an toàn qua useXssFilter hoặc plain text qua isInnerText
  • Tích hợp Tooltip (Popover) hiển thị nội dung đầy đủ khi hover
  • Hiệu ứng gradient mờ dần ở cuối đoạn văn bị cắt (hasBackgroundGradient)
  • Tự động refresh khi cửa sổ trình duyệt resize (window:resize)
  • Cho phép tùy chỉnh nhãn nút, CSS class nội dung và nút điều khiển
  • Cung cấp FunctionsControl (refresh, viewMore, hiddenMore, checkIsDisplayLineClamp) để điều khiển từ bên ngoài
  • Hỗ trợ i18n thông qua @ngx-translate/core

Khi nào sử dụng

  • Hiển thị phần giới thiệu ngắn trong danh sách thẻ (Card list) khi không đủ không gian
  • Cắt bớt bình luận, mô tả sản phẩm hoặc ghi chú dài trong giao diện Dashboard
  • Cần render HTML từ backend nhưng vẫn đảm bảo an toàn XSS và hỗ trợ rút gọn
  • Muốn người dùng xem nhanh nội dung đầy đủ qua Tooltip mà không cần mở rộng trang

Cài đặt

npm install @libs-ui/components-line-clamp

Import

import { LibsUiComponentsLineClampComponent } from '@libs-ui/components-line-clamp';
import { ILineClampFunctionControlEvent, ILineClampConfig } from '@libs-ui/components-line-clamp';

@Component({
  standalone: true,
  imports: [LibsUiComponentsLineClampComponent],
})
export class YourComponent {}

Ví dụ sử dụng

Cắt dòng cơ bản (2 dòng, line-height 20px)

// your.component.ts
import { Component } from '@angular/core';
import { LibsUiComponentsLineClampComponent } from '@libs-ui/components-line-clamp';

@Component({
  standalone: true,
  imports: [LibsUiComponentsLineClampComponent],
  template: `
    <libs_ui-components-line_clamp
      [content]="longText"
      [maxHeight]="40"
      [labelButtonViewMore]="'Xem thêm nội dung'"
      [labelButtonCollapse]="'Thu gọn lại'">
    </libs_ui-components-line_clamp>
  `,
})
export class BasicExampleComponent {
  readonly longText = `Angular là một nền tảng và framework để xây dựng các ứng dụng khách đơn trang
    sử dụng HTML và TypeScript. Nó triển khai chức năng cốt lõi và tùy chọn dưới dạng
    một tập hợp các thư viện TypeScript mà bạn import vào ứng dụng của mình.`;
}

Tooltip và hiệu ứng gradient

// your.component.ts
import { Component } from '@angular/core';
import { LibsUiComponentsLineClampComponent } from '@libs-ui/components-line-clamp';

@Component({
  standalone: true,
  imports: [LibsUiComponentsLineClampComponent],
  template: `
    <libs_ui-components-line_clamp
      [content]="htmlContent"
      [maxHeight]="60"
      [showTooltip]="true"
      [hasBackgroundGradient]="true"
      [maxWidthTooltip]="350"
      [directionTooltip]="'bottom'">
    </libs_ui-components-line_clamp>
  `,
})
export class TooltipExampleComponent {
  readonly htmlContent = `
    <p style="color: #ef4444; font-weight: bold;">Nội dung HTML quan trọng:</p>
    <ul>
      <li>Signal là một cách mới để quản lý state.</li>
      <li>Control Flow Syntax giúp template sạch hơn.</li>
      <li>Deferrable Views giúp tối ưu lazy loading.</li>
    </ul>
  `;
}

Plain text mode (không render HTML)

// your.component.ts
import { Component } from '@angular/core';
import { LibsUiComponentsLineClampComponent } from '@libs-ui/components-line-clamp';

@Component({
  standalone: true,
  imports: [LibsUiComponentsLineClampComponent],
  template: `
    <libs_ui-components-line_clamp
      [content]="plainText"
      [maxHeight]="40"
      [isInnerText]="true"
      [ngClassObject]="{ 'text-gray-500 italic': true }">
    </libs_ui-components-line_clamp>
  `,
})
export class PlainTextExampleComponent {
  readonly plainText = `Đây là văn bản thuần túy, sẽ được render bằng innerText.
    Mọi thẻ HTML trong chuỗi này sẽ hiển thị dưới dạng ký tự thay vì được phân tích cú pháp.`;
}

Điều khiển từ component cha qua FunctionsControl

// parent.component.ts
import { Component, signal, viewChild } from '@angular/core';
import {
  LibsUiComponentsLineClampComponent,
  ILineClampFunctionControlEvent,
} from '@libs-ui/components-line-clamp';

@Component({
  standalone: true,
  imports: [LibsUiComponentsLineClampComponent],
  template: `
    <libs_ui-components-line_clamp
      [content]="description"
      [maxHeight]="60"
      (outFunctionControl)="handlerFunctionControl($event)"
      (outAction)="handlerAction($event)"
      (outDisplayLineClamp)="handlerDisplayLineClamp($event)">
    </libs_ui-components-line_clamp>

    <button (click)="handlerRefresh()">Refresh</button>
    <button (click)="handlerExpandAll()">Mở rộng tất cả</button>
  `,
})
export class ParentExampleComponent {
  protected description = `Mô tả dài của sản phẩm sẽ được cắt sau 3 dòng (60px với line-height 20px).
    Nhấn nút bên dưới để điều khiển trạng thái từ component cha.`;

  private lineClampControl: ILineClampFunctionControlEvent | undefined;

  protected handlerFunctionControl(control: ILineClampFunctionControlEvent): void {
    this.lineClampControl = control;
  }

  protected handlerAction(action: string): void {
    // action: 'view-more' | 'hidden-more'
    console.log('Line clamp action:', action);
  }

  protected handlerDisplayLineClamp(isCollapsed: boolean): void {
    console.log('Is collapsed:', isCollapsed);
  }

  protected handlerRefresh(): void {
    this.lineClampControl?.refresh();
  }

  protected handlerExpandAll(): void {
    this.lineClampControl?.viewMore();
  }
}

Ẩn nút thu gọn (chỉ hiển thị "Xem thêm")

<libs_ui-components-line_clamp
  [content]="shortDescription"
  [maxHeight]="40"
  [ignoreShowButtonCollapse]="true"
  [labelButtonViewMore]="'Đọc thêm'">
</libs_ui-components-line_clamp>

@Input()

| Input | Type | Default | Mô tả | Ví dụ | |---|---|---|---|---| | classClassIncludeButtonCollapseExpand | string | '!p-0' | Class CSS cho container wrapper của nút collapse/expand | [classClassIncludeButtonCollapseExpand]="'mt-2 !p-0'" | | classClassLabelButtonCollapseExpand | string | 'libs-ui-font-h5r' | Class CSS typography cho nhãn nút collapse/expand | [classClassLabelButtonCollapseExpand]="'libs-ui-font-h6r'" | | content | string | bắt buộc | Nội dung văn bản hoặc HTML cần hiển thị và cắt ngắn | [content]="description" | | defaultIsCollapse | boolean | true | Trạng thái thu gọn mặc định khi nội dung vượt maxHeight | [defaultIsCollapse]="false" | | directionTooltip | TYPE_POPOVER_DIRECTION | 'top' | Hướng xuất hiện của Tooltip (top, bottom, left, right) | [directionTooltip]="'bottom'" | | hasBackgroundGradient | boolean | false | Hiển thị hiệu ứng mờ dần gradient ở cuối đoạn văn bị cắt | [hasBackgroundGradient]="true" | | ignoreShowButtonCollapse | boolean | undefined | Ẩn nút "Thu gọn", chỉ giữ lại nút "Xem thêm" | [ignoreShowButtonCollapse]="true" | | ignoreShowButtonCollapseExpand | boolean | false | Ẩn hoàn toàn cả hai nút Xem thêm và Thu gọn | [ignoreShowButtonCollapseExpand]="true" | | ignoreStopPropagationTooltipEvent | boolean | false | Cho phép sự kiện Tooltip nổi bọt lên component cha | [ignoreStopPropagationTooltipEvent]="true" | | isInnerText | boolean | undefined | Render nội dung bằng innerText thay vì innerHTML, mọi thẻ HTML sẽ hiển thị dạng ký tự | [isInnerText]="true" | | labelButtonCollapse | string | undefined (dùng i18n i18n_collapse) | Nhãn tùy chỉnh cho nút Thu gọn | [labelButtonCollapse]="'Thu gọn lại'" | | labelButtonViewMore | string | undefined (dùng i18n i18n_view_more) | Nhãn tùy chỉnh cho nút Xem thêm | [labelButtonViewMore]="'Xem thêm nội dung'" | | lengthLimitDisplay | number | 200 | Giới hạn số ký tự dùng để tính toán cắt chuỗi ban đầu trước khi đo DOM | [lengthLimitDisplay]="300" | | maxHeight | number | bắt buộc | Chiều cao tối đa (px) trước khi cắt. Công thức: line-height × số dòng. Ví dụ: 20px × 3 dòng = 60 | [maxHeight]="60" | | maxHeightTooltip | number | 150 | Chiều cao tối đa (px) của Tooltip | [maxHeightTooltip]="200" | | maxWidthTooltip | number | 250 | Chiều rộng tối đa (px) của Tooltip | [maxWidthTooltip]="350" | | ngClassObject | TYPE_OBJECT | { 'libs-ui-line-clamp-content libs-ui-font-h5r': true } | Object ngClass để apply class CSS vào div chứa nội dung | [ngClassObject]="{ 'libs-ui-font-h6r text-gray-700': true }" | | showTooltip | boolean | undefined | Bật Tooltip hiển thị toàn bộ nội dung khi hover vào vùng văn bản đã cắt | [showTooltip]="true" | | timeHidePopoverOnMouseout | number | 50 | Thời gian delay (ms) trước khi ẩn Tooltip sau sự kiện mouseout | [timeHidePopoverOnMouseout]="100" | | useXssFilter | boolean | true | Bật bộ lọc XSS cho nội dung HTML (chỉ có hiệu lực khi isInnerTextfalse) | [useXssFilter]="false" | | zIndexPopover | number | 1001 | Giá trị z-index của Tooltip/Popover | [zIndexPopover]="1050" |

@Output()

| Output | Type | Mô tả | Handler TS | Binding HTML | |---|---|---|---|---| | (outAction) | string | Phát ra chuỗi 'view-more' khi nhấn nút Xem thêm, hoặc 'hidden-more' khi nhấn nút Thu gọn | handlerAction(action: string): void { console.log(action); } | (outAction)="handlerAction($event)" | | (outClick) | Event \| TYPE_POPOVER_EVENT | Phát ra khi người dùng click vào vùng nội dung (giá trị là Event) hoặc khi Tooltip nhận sự kiện click (giá trị là chuỗi 'click' từ TYPE_POPOVER_EVENT) | handlerClick(event: Event \| string): void { if (event instanceof Event) { event.stopPropagation(); } console.log(event); } | (outClick)="handlerClick($event)" | | (outDisplayLineClamp) | boolean | Phát ra trạng thái thu gọn hiện tại (true = đang thu gọn, false = đã mở rộng). Kích hoạt khi nội dung vượt maxHeight | handlerDisplayLineClamp(isCollapsed: boolean): void { this.isCollapsed.set(isCollapsed); } | (outDisplayLineClamp)="handlerDisplayLineClamp($event)" | | (outFunctionControl) | ILineClampFunctionControlEvent | Phát ra ngay khi component khởi tạo (ngOnInit), cung cấp các method điều khiển để component cha gọi từ bên ngoài | handlerFunctionControl(control: ILineClampFunctionControlEvent): void { this.lineClampControl = control; } | (outFunctionControl)="handlerFunctionControl($event)" |

Types & Interfaces

import {
  ILineClampFunctionControlEvent,
  ILineClampConfig,
} from '@libs-ui/components-line-clamp';

ILineClampFunctionControlEvent

Interface nhận được qua event (outFunctionControl), dùng để điều khiển component từ bên ngoài:

export interface ILineClampFunctionControlEvent {
  /** Làm mới trạng thái, tính toán lại từ đầu */
  refresh: () => Promise<void>;

  /** Kiểm tra component có đang ở trạng thái clamp (nội dung bị cắt) không */
  checkIsDisplayLineClamp: () => Promise<boolean>;

  /** Mở rộng nội dung (tương đương nhấn nút "Xem thêm") */
  viewMore: () => Promise<void>;

  /** Thu gọn nội dung (tương đương nhấn nút "Thu gọn") */
  hiddenMore: () => Promise<void>;
}

ILineClampConfig

Interface cấu hình tùy chọn (dùng cho các trường hợp cần type hóa config object):

import { TYPE_OBJECT } from '@libs-ui/interfaces-types';

export interface ILineClampConfig {
  maxHeight?: number;
  class?: string;
  ignoreShowButtonCollapseExpand?: boolean;
  showTooltip?: boolean;
  maxWidthTooltip?: number;
  maxHeightTooltip?: number;
  ngClassObject?: TYPE_OBJECT;
  isInnerText?: boolean;
}

Lưu ý quan trọng

⚠️ Tính toán maxHeight: maxHeight phải bằng line-height (px) × số dòng mong muốn. Ví dụ: text có line-height: 20px, muốn hiển thị 3 dòng thì set [maxHeight]="60". Sai giá trị này sẽ khiến việc phát hiện clamp không chính xác.

⚠️ isInnerText và useXssFilter: Khi bật [isInnerText]="true", nội dung được render bằng innerText — mọi thẻ HTML đều hiển thị dưới dạng ký tự. Trong trường hợp này useXssFilter không có tác dụng. Chỉ dùng useXssFilter khi render HTML (mặc định).

⚠️ ngClassObject — CSS typography: Object ngClassObject được apply vào thẻ div bao quanh nội dung. Mặc định là { 'libs-ui-line-clamp-content libs-ui-font-h5r': true }. Khi ghi đè, cần bao gồm cả class layout cần thiết, không chỉ class typography.

⚠️ outFunctionControl phát ra khi ngOnInit: Event (outFunctionControl) chỉ phát ra một lần duy nhất khi component khởi tạo. Cần lưu lại reference để dùng sau: private lineClampControl: ILineClampFunctionControlEvent | undefined.

⚠️ Resize tự động: Component lắng nghe sự kiện window:resize và tự động gọi refresh(). Việc này đảm bảo trạng thái clamp luôn chính xác khi kích thước viewport thay đổi.