Chuyển tới nội dung

Pro đang mở bán trước. Cài đặt mở từ tháng 1/2027. Xem Pro

Component

Skeleton

Một khối xám giữ chỗ cho nội dung trong lúc tải, đúng hình và đúng cỡ của thứ sẽ thay nó: một dòng chữ, một avatar, một control, một ảnh. Khối nhấp, trừ khi người dùng yêu cầu giảm chuyển động.

  • npm: 1 trực tiếp, 2 tổng
  • registry: 2 trực tiếp, 2 tổng

Xem trước

Props

  • shape
  • size
  • width
  • height
  • lines
import { Skeleton } from "@/components/ui/skeleton"

<Skeleton lines={2} className="w-64 text-sm min-w-0 max-w-full" />

Cách dùng

Khi nào dùng

  • Giữ chỗ cho nội dung mà bạn biết bố cục trong lúc tải: một danh sách bình luận, một card, một hồ sơ.
  • Giữ trang không nhảy khi nội dung vào.

Khi nào không dùng

  • Một hành động chỉ mất một lúc, như đang lưu. Dùng Spinner.
  • Việc đã biết lượng, như một lần tải lên. Dùng Progress.

Biến thể

shape

text đứng thay một dòng chữ xung quanh; circular cho một avatar; control cho một Button, Input hoặc Select; rectangular cho một ảnh hoặc một khối media.

  • textmặc định

  • circular

  • rectangular

  • control

import { Skeleton } from "@/components/ui/skeleton"

<Skeleton lines={2} className="w-64 text-sm min-w-0 max-w-full" />
<Skeleton shape="circular" className="min-w-0 max-w-full" />
<Skeleton shape="rectangular" className="w-64 min-w-0 max-w-full" />
<Skeleton shape="control" className="w-64 min-w-0 max-w-full" />

size

Chỉ circular và control. circular lấy size của Avatar (24, 32, 40px; Avatar không có xl, nên xl là vòng lg 40px); control lấy chiều cao element, nên khớp control cùng size.

  • sm

  • mdmặc định

  • lg

  • xl

import { Skeleton } from "@/components/ui/skeleton"

<Skeleton lines={2} className="w-64 text-sm min-w-0 max-w-full" />
<Skeleton lines={2} className="w-64 text-sm min-w-0 max-w-full" />
<Skeleton lines={2} className="w-64 text-sm min-w-0 max-w-full" />
<Skeleton lines={2} className="w-64 text-sm min-w-0 max-w-full" />

Ví dụ

Một bình luận đang tải

Một avatar và hai dòng chữ, theo bố cục của bình luận sẽ thay chúng.

Loading
import { Skeleton, SkeletonGroup } from "@/components/ui/skeleton"

<SkeletonGroup className="flex w-full items-start gap-md min-w-0 max-w-full">
  <Skeleton shape="circular" className="min-w-0 max-w-full" />
  <div className="flex flex-1 flex-col text-sm">
    <Skeleton className="w-32 min-w-0 max-w-full" />
    <Skeleton lines={2} className="min-w-0 max-w-full" />
  </div>
</SkeletonGroup>

Một card đang tải

Loading
import { Skeleton, SkeletonGroup } from "@/components/ui/skeleton"

<SkeletonGroup className="flex w-64 flex-col gap-md min-w-0 max-w-full">
  <Skeleton shape="rectangular" className="min-w-0 max-w-full" />
  <Skeleton className="text-sm w-40 min-w-0 max-w-full" />
</SkeletonGroup>

Một form đang tải

Một dòng label đúng cỡ của label và một control đúng cỡ của field, để form không dịch khi nội dung tới.

Đang tải cài đặt
import { Skeleton, SkeletonGroup } from "@/components/ui/skeleton"

<SkeletonGroup label="Đang tải cài đặt" className="flex w-64 flex-col gap-sm min-w-0 max-w-full">
  <Skeleton className="w-24 text-sm min-w-0 max-w-full" />
  <Skeleton shape="control" className="min-w-0 max-w-full" />
</SkeletonGroup>

Nên và không nên

Nên

  • Khớp bố cục của nội dung sẽ thay nó, để không gì nhảy khi tải xong: dòng chữ cùng font size, control cùng size, cùng góc.
  • Dùng lines cho một đoạn: dòng cuối ngắn hơn, như chữ thật.
  • Bọc vùng trong SkeletonGroup, hoặc bạn tự đặt aria-busy và một status polite "Đang tải".
  • Chỉ hiện khi việc tải lâu hơn khoảng 150ms, và giữ ít nhất khoảng 300ms sau khi đã hiện (useSkeletonDelay), để nó không nháy.
  • Với một tab, một trang của bảng hoặc một bộ lọc, giữ nội dung trước trên màn hình bằng trạng thái pending thay vì skeleton.

Không nên

  • Đừng dùng cho một hành động chỉ mất một lúc, như đang lưu. Dùng Spinner.
  • Đừng dùng khi biết lượng việc, như một lần tải lên. Dùng Progress.
  • Đừng đặt chữ, icon hoặc control bên trong.
  • Đừng xóa nội dung đã có trên màn hình để hiện skeleton.

Props

TênKiểuGiá trịMặc địnhMô tả
shapeenumtext | circular | rectangular | controltexttext đứng thay một dòng chữ xung quanh; circular cho một avatar; control cho một Button, Input hoặc Select; rectangular cho một ảnh hoặc một khối media.
sizeenumsm | md | lg | xlmdChỉ circular và control. circular lấy size của Avatar (24, 32, 40px; Avatar không có xl, nên xl là vòng lg 40px); control lấy chiều cao element, nên khớp control cùng size.
widthstring--Chiều rộng cho giá trị chỉ biết lúc chạy, như chiều rộng một cột. Nếu không thì đặt class size bằng className (w-48).
heightstring--Chiều cao cho giá trị chỉ biết lúc chạy. Nếu không thì đặt class size bằng className (h-24). Khi có lines, đây là chiều cao của mỗi dòng.
linesnumber-1Chỉ text: bấy nhiêu dòng trong một cột, dòng cuối ngắn hơn, như cuối một đoạn. className và width đặt trên cột.
labelstring-LoadingChỉ SkeletonGroup: thứ trình đọc màn hình nghe trong lúc vùng đang tải.

Cấu tạo

PhầnMô tả
rootKhối với nền xám nhạt. text là hộp cao một dòng (line height của font size đó), với một thanh cao một em ở giữa và góc inner; circular là vòng tròn cỡ Avatar; control là khối cỡ control (chiều cao element, góc element); rectangular hết chiều rộng, tỷ lệ 16 trên 9, với góc element.
barChỉ text: thanh bên trong hộp dòng, vẽ bằng ::before.
linesKhi có lines: cột giữ các dòng, không có gap, nên cao bằng đúng số dòng thật đó. Dòng cuối rộng hai phần ba.
groupSkeletonGroup: vùng đang tải, có aria-busy, và một status polite giấu khỏi mắt đặt cạnh vùng, đọc label.

Khả năng truy cập

Role: none

  • Bị ẩn với trình đọc màn hình (aria-hidden). Vùng đang tải đặt aria-busy="true" và nói "Đang tải" trong một status polite; SkeletonGroup làm cả hai. Gỡ cả hai khi nội dung đã vào.
  • Nhịp là một vòng opacity canh theo duration-loop, và không chạy khi có prefers-reduced-motion; khối vẫn ở đó.
  • Không bao giờ focus được. Control trong vùng đang tải đứng ngoài thứ tự Tab đến khi chúng tồn tại.

Cài đặt

npx werewolf-ui add skeleton

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.