К содержимому
uiify

Table

Нативная таблица с необязательным интерактивным адаптером.

Браузеры
Chrome 123+Firefox 121+Safari 17.5+
Уровень
0
Сжатый размер
617 B
Лимит принудительной компоновки
0 ms
Лимит axe
0
Совместим с SSR
Да
Публичный контракт
Тестовый стенд

Песочница

Table

Пример нативной таблицы

Участники команды
ИмяРольСтатус
Alice ChenАдминистраторАктивен
Bob SmithРедакторАктивен
Carol LeeНаблюдательПриглашён
3 участника · 2 активных

Сортировка, фильтрация и раскрытие

РольПодробнее
Alice ChenАдминистратор
Bob SmithРедактор
Carol LeeНаблюдатель
Участников: 3 · выбрано: 0

Закреплённые заголовки, подвал и столбцы

Участник 1Редакторmember1@example.comАктивен
Участник 2Редакторmember2@example.comАктивен
Участник 3Редакторmember3@example.comАктивен
Участник 4Редакторmember4@example.comАктивен
Участник 5Редакторmember5@example.comАктивен
Участник 6Редакторmember6@example.comАктивен
Участник 7Редакторmember7@example.comАктивен
Участник 8Редакторmember8@example.comАктивен
Участник 9Редакторmember9@example.comАктивен
Участник 10Редакторmember10@example.comАктивен
Участник 11Редакторmember11@example.comАктивен
Участник 12Редакторmember12@example.comАктивен
Участник 13Редакторmember13@example.comАктивен
Участник 14Редакторmember14@example.comАктивен
Участник 15Редакторmember15@example.comАктивен
Участник 16Редакторmember16@example.comАктивен
Участник 17Редакторmember17@example.comАктивен
Участник 18Редакторmember18@example.comАктивен
Участник 19Редакторmember19@example.comАктивен
Участник 20Редакторmember20@example.comАктивен
Участник 21Редакторmember21@example.comАктивен
Участник 22Редакторmember22@example.comАктивен
Участник 23Редакторmember23@example.comАктивен
Участник 24Редакторmember24@example.comАктивен
24 участника
import { Table } from "@gunkin/uiify";
const rows = [
  { id: "alice", name: "Alice Chen", role: "Admin", status: "Active" },
  { id: "bob", name: "Bob Smith", role: "Editor", status: "Active" },
  { id: "carol", name: "Carol Lee", role: "Viewer", status: "Invited" },
];
export default function Example() {
  return (
    <Table.Root className="" variant="outline" size="sm">
      <Table.Caption>Team members</Table.Caption>
      <Table.Header>
        <Table.Row id="team-head">
          <Table.ColumnHeader id="team-name">Name</Table.ColumnHeader>
          <Table.ColumnHeader id="team-role">Role</Table.ColumnHeader>
          <Table.ColumnHeader id="team-status">Status</Table.ColumnHeader>
        </Table.Row>
      </Table.Header>
      <Table.Body>
        {rows.map((row) => (
          <Table.Row id={row.id} key={row.id}>
            <Table.RowHeader>{row.name}</Table.RowHeader>
            <Table.Cell>{row.role}</Table.Cell>
            <Table.Cell>{row.status}</Table.Cell>
          </Table.Row>
        ))}
      </Table.Body>
      <Table.Footer>
        <Table.Row id="team-total">
          <Table.Cell colSpan={3}>3 members · 2 active</Table.Cell>
        </Table.Row>
      </Table.Footer>
    </Table.Root>
  );
}
@layer components {
  [data-uiify-table] {
    inline-size: 100%;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--card);
    color: var(--card-foreground);
    font-size: var(--text-sm);
  }
  [data-uiify-table][data-layout="fixed"] {
    table-layout: fixed;
  }
  [data-uiify-table] :is(th, td) {
    padding-block: 0.75rem;
    padding-inline: 1rem;
    text-align: start;
    vertical-align: middle;
    border-block-end: 1px solid var(--border);
    background: inherit;
  }
  [data-uiify-table] :is(th, td)[data-align="center"] {
    text-align: center;
  }
  [data-uiify-table] :is(th, td)[data-align="end"] {
    text-align: end;
  }
  [data-uiify-table] :is(thead, tfoot) {
    background: var(--secondary);
    font-weight: 600;
  }
  [data-uiify-table] tbody tr {
    background: var(--card);
  }
  [data-uiify-table] tbody tr:hover {
    background: var(--secondary);
  }
  [data-uiify-table] tbody tr[data-selected] {
    background: var(--accent);
  }
  [data-uiify-table] caption {
    padding-block: 0.75rem;
    text-align: start;
    color: var(--muted-foreground);
  }
  [data-uiify-table][data-size="sm"] :is(th, td) {
    padding-block: 0.5rem;
    padding-inline: 0.75rem;
  }
  [data-uiify-table][data-size="lg"] :is(th, td) {
    padding-block: 1rem;
    padding-inline: 1.25rem;
  }
  [data-uiify-table][data-variant="outline"] {
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
  }
  [data-uiify-table][data-variant="ghost"] {
    background: transparent;
  }
  [data-uiify-table] :is(thead, tfoot, tr)[data-sticky] {
    position: sticky;
    inset-block-start: var(--uiify-table-sticky-offset, 0);
    z-index: 2;
  }
  [data-uiify-table] tfoot[data-sticky] {
    inset-block: auto var(--uiify-table-sticky-offset, 0);
  }
  [data-uiify-table] :is(th, td)[data-sticky] {
    position: sticky;
    z-index: 1;
  }
  [data-uiify-table] :is(th, td)[data-sticky="start"] {
    inset-inline-start: var(--uiify-table-sticky-offset, 0);
  }
  [data-uiify-table] :is(th, td)[data-sticky="end"] {
    inset-inline-end: var(--uiify-table-sticky-offset, 0);
  }
  [data-uiify-table] :is(thead, tfoot)[data-sticky] :is(th, td)[data-sticky] {
    z-index: 3;
  }
  [data-uiify-table] th > button {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    cursor: pointer;
  }
  [data-uiify-table] th[aria-sort="ascending"] > button::after {
    content: "↑" / "";
  }
  [data-uiify-table] th[aria-sort="descending"] > button::after {
    content: "↓" / "";
  }
  [data-uiify-table] [data-part="expanded-row"] {
    background: var(--secondary);
  }
  [data-uiify-table] :is(button, tr):focus-visible {
    outline: 2px solid var(--ring);
    outline-offset: -2px;
  }
}
import { Table } from "@gunkin/uiify";
const rows = [
  { id: "alice", name: "Alice Chen", role: "Admin", status: "Active" },
  { id: "bob", name: "Bob Smith", role: "Editor", status: "Active" },
  { id: "carol", name: "Carol Lee", role: "Viewer", status: "Invited" },
];
export default function Example() {
  return (
    <Table.Root
      className={
        "[inline-size:100%] [border-collapse:separate] [border-spacing:0] bg-card text-card-foreground text-sm data-" +
        "[layout=fixed]:table-fixed [&_:is(th,td)]:[padding-block:0.75rem] [&_:is(th,td)]:[padding-inline:1rem] [&_:" +
        "is(th,td)]:text-start [&_:is(th,td)]:[vertical-align:middle] [&_:is(th,td)]:[border-block-end-width:1px] [&" +
        "_:is(th,td)]:[border-block-end-style:solid] [&_:is(th,td)]:[border-block-end-color:var(--border)] [&_:is(th" +
        ",td)]:[background:inherit] [&_:is(th,td)[data-align=center]]:text-center [&_:is(th,td)[data-align=end]]:tex" +
        "t-end [&_:is(thead,tfoot)]:bg-secondary [&_:is(thead,tfoot)]:[font-weight:600] [&_tbody_tr]:bg-card [&_tbod" +
        "y_tr:hover]:bg-secondary [&_tbody_tr[data-selected]]:bg-accent [&_caption]:[padding-block:0.75rem] [&_capti" +
        "on]:text-start [&_caption]:text-muted-foreground [&[data-size=sm]_:is(th,td)]:[padding-block:0.5rem] [&[dat" +
        "a-size=sm]_:is(th,td)]:[padding-inline:0.75rem] [&[data-size=lg]_:is(th,td)]:[padding-block:1rem] [&[data-s" +
        "ize=lg]_:is(th,td)]:[padding-inline:1.25rem] data-[variant=outline]:[border-width:1px] data-[variant=outlin" +
        "e]:border-solid data-[variant=outline]:border-border data-[variant=outline]:rounded-lg data-[variant=ghost]" +
        ":bg-transparent [&_:is(thead,tfoot,tr)[data-sticky]]:sticky [&_:is(thead,tfoot,tr)[data-sticky]]:[inset-blo" +
        "ck-start:var(--uiify-table-sticky-offset,_0)] [&_:is(thead,tfoot,tr)[data-sticky]]:z-[2] [&_tfoot[data-stic" +
        "ky]]:[inset-block:auto_var(--uiify-table-sticky-offset,_0)] [&_:is(th,td)[data-sticky]]:sticky [&_:is(th,td" +
        ")[data-sticky]]:z-[1] [&_:is(th,td)[data-sticky=start]]:[inset-inline-start:var(--uiify-table-sticky-offset" +
        ",_0)] [&_:is(th,td)[data-sticky=end]]:[inset-inline-end:var(--uiify-table-sticky-offset,_0)] [&_:is(thead,t" +
        "foot)[data-sticky]_:is(th,td)[data-sticky]]:z-[3] [&_th>button]:inline-flex [&_th>button]:items-center [&_t" +
        "h>button]:[gap:0.5rem] [&_th>button]:p-0 [&_th>button]:border-0 [&_th>button]:border-current [&_th>button]:" +
        "border-none [&_th>button]:bg-transparent [&_th>button]:text-inherit [&_th>button]:[font-style:inherit] [&_t" +
        "h>button]:[font-variant:inherit] [&_th>button]:[font-weight:inherit] [&_th>button]:[font-stretch:inherit] [" +
        "&_th>button]:text-[length:inherit] [&_th>button]:leading-[inherit] [&_th>button]:font-[family-name:inherit]" +
        " [&_th>button]:cursor-pointer [&_th[aria-sort=ascending]>button::after]:content-[\"↑\"_/_\"\"] [&_th[aria-sort=" +
        "descending]>button::after]:content-[\"↓\"_/_\"\"] [&_[data-part=expanded-row]]:bg-secondary [&_:is(button,tr):f" +
        "ocus-visible]:[outline:2px_solid_var(--ring)] [&_:is(button,tr):focus-visible]:[outline-offset:-2px]"
      }
      variant="outline"
      size="sm"
    >
      <Table.Caption>Team members</Table.Caption>
      <Table.Header>
        <Table.Row id="team-head">
          <Table.ColumnHeader id="team-name">Name</Table.ColumnHeader>
          <Table.ColumnHeader id="team-role">Role</Table.ColumnHeader>
          <Table.ColumnHeader id="team-status">Status</Table.ColumnHeader>
        </Table.Row>
      </Table.Header>
      <Table.Body>
        {rows.map((row) => (
          <Table.Row id={row.id} key={row.id}>
            <Table.RowHeader>{row.name}</Table.RowHeader>
            <Table.Cell>{row.role}</Table.Cell>
            <Table.Cell>{row.status}</Table.Cell>
          </Table.Row>
        ))}
      </Table.Body>
      <Table.Footer>
        <Table.Row id="team-total">
          <Table.Cell colSpan={3}>3 members · 2 active</Table.Cell>
        </Table.Row>
      </Table.Footer>
    </Table.Root>
  );
}
/* app.css */

@layer reset, ui, app, tokens, base, demo, components, utilities, theme;

@import "@gunkin/uiify/styles/reset";

@import "@gunkin/uiify/components/behavior.css";

@import "@gunkin/uiify/styles/tokens";

@import "@gunkin/uiify/styles/tailwind";

@import "tailwindcss/utilities.css";

@theme { --spacing: 0.25rem; --font-weight-normal: 400; --font-weight-medium: 500; --font-weight-semibold: 600; --font-weight-bold: 700; }

@source inline('[inline-size:100%] [border-collapse:separate] [border-spacing:0] bg-card text-card-foreground text-sm data-[layout=fixed]:table-fixed [&_:is(th,td)]:[padding-block:0.75rem] [&_:is(th,td)]:[padding-inline:1rem] [&_:is(th,td)]:text-start [&_:is(th,td)]:[vertical-align:middle] [&_:is(th,td)]:[border-block-end-width:1px] [&_:is(th,td)]:[border-block-end-style:solid] [&_:is(th,td)]:[border-block-end-color:var(--border)] [&_:is(th,td)]:[background:inherit] [&_:is(th,td)[data-align=center]]:text-center [&_:is(th,td)[data-align=end]]:text-end [&_:is(thead,tfoot)]:bg-secondary [&_:is(thead,tfoot)]:[font-weight:600] [&_tbody_tr]:bg-card [&_tbody_tr:hover]:bg-secondary [&_tbody_tr[data-selected]]:bg-accent [&_caption]:[padding-block:0.75rem] [&_caption]:text-start [&_caption]:text-muted-foreground [&[data-size=sm]_:is(th,td)]:[padding-block:0.5rem] [&[data-size=sm]_:is(th,td)]:[padding-inline:0.75rem] [&[data-size=lg]_:is(th,td)]:[padding-block:1rem] [&[data-size=lg]_:is(th,td)]:[padding-inline:1.25rem] data-[variant=outline]:[border-width:1px] data-[variant=outline]:border-solid data-[variant=outline]:border-border data-[variant=outline]:rounded-lg data-[variant=ghost]:bg-transparent [&_:is(thead,tfoot,tr)[data-sticky]]:sticky [&_:is(thead,tfoot,tr)[data-sticky]]:[inset-block-start:var(--uiify-table-sticky-offset,_0)] [&_:is(thead,tfoot,tr)[data-sticky]]:z-[2] [&_tfoot[data-sticky]]:[inset-block:auto_var(--uiify-table-sticky-offset,_0)] [&_:is(th,td)[data-sticky]]:sticky [&_:is(th,td)[data-sticky]]:z-[1] [&_:is(th,td)[data-sticky=start]]:[inset-inline-start:var(--uiify-table-sticky-offset,_0)] [&_:is(th,td)[data-sticky=end]]:[inset-inline-end:var(--uiify-table-sticky-offset,_0)] [&_:is(thead,tfoot)[data-sticky]_:is(th,td)[data-sticky]]:z-[3] [&_th>button]:inline-flex [&_th>button]:items-center [&_th>button]:[gap:0.5rem] [&_th>button]:p-0 [&_th>button]:border-0 [&_th>button]:border-current [&_th>button]:border-none [&_th>button]:bg-transparent [&_th>button]:text-inherit [&_th>button]:[font-style:inherit] [&_th>button]:[font-variant:inherit] [&_th>button]:[font-weight:inherit] [&_th>button]:[font-stretch:inherit] [&_th>button]:text-[length:inherit] [&_th>button]:leading-[inherit] [&_th>button]:font-[family-name:inherit] [&_th>button]:cursor-pointer [&_th[aria-sort=ascending]>button::after]:content-["↑"_/_""] [&_th[aria-sort=descending]>button::after]:content-["↓"_/_""] [&_[data-part=expanded-row]]:bg-secondary [&_:is(button,tr):focus-visible]:[outline:2px_solid_var(--ring)] [&_:is(button,tr):focus-visible]:[outline-offset:-2px]');

@layer base { :root { --uiify-control-text: var(--text-sm); } @media (pointer: coarse) { :root { --uiify-control-text: var(--text-base); } } }

/* Authored animation and registered properties used by the Tailwind skin.
 * Visual rules belong in utility recipes; only at-rule definitions live here. */
@layer components {
  @keyframes uiify-presence-in {
    from {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@layer components {
  @keyframes uiify-presence-out {
    to {
      opacity: 0;
      scale: var(--presence-scale);
    }
  }
}

@property --uiify-spinner-tail {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@property --uiify-spinner-length {
  syntax: "<angle>";
  inherits: false;
  initial-value: 36deg;
}

@layer components {
  @keyframes uiify-spinner-rotate {
    to {
      transform: rotate(360deg);
    }
  }
}

@layer components {
  @keyframes uiify-spinner-orbit {
    0% {
      --uiify-spinner-tail: 0deg;
      --uiify-spinner-length: 36deg;
    }

    50% {
      --uiify-spinner-tail: 90deg;
      --uiify-spinner-length: 324deg;
    }

    100% {
      --uiify-spinner-tail: 360deg;
      --uiify-spinner-length: 36deg;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-pulse {
    50% {
      opacity: 0.45;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-shimmer {
    to {
      background-position: -200% 0;
    }
  }
}

@layer components {
  @keyframes uiify-skeleton-reveal {
    from {
      opacity: 0;
    }
    to {
      opacity: 1;
    }
  }
}

@property --candle-body-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-body-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-slot {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 100%;
}

@property --candle-wick-height {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-wick-top {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --candle-x {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 0%;
}

@property --candle-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@property --line-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-prev-y {
  syntax: "<percentage>";
  inherits: true;
  initial-value: 50%;
}

@property --line-count {
  syntax: "<integer>";
  inherits: false;
  initial-value: 1;
}

@property --line-scale {
  syntax: "<number>";
  inherits: true;
  initial-value: 1;
}

@layer components {
  @keyframes uiify-otp-input-caret-blink {
    50% {
      opacity: 0;
    }
  }
}

API

Table.Root (native)

СвойствоТипПо умолчаниюОписание
layout"auto" | "fixed""auto"Нативная компоновка таблицы. Выбор, сортировка и раскрытие используют отдельную точку входа TableClient.
size"sm" | "md" | "lg"—Интервалы ячеек из выбранной таблицы стилей.
variant"solid" | "outline" | "ghost"—Вариант поверхности из выбранной таблицы стилей.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.Footer

СвойствоТипПо умолчаниюОписание
stickyboolean—Закрепляет подвал в конце блочной оси контейнера прокрутки.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.RowHeader / Table.Cell / Table.ColumnHeader

СвойствоТипПо умолчаниюОписание
align"start" | "center" | "end""start"Логическое выравнивание текста в ячейке.
sticky"start" | "end"—Закрепляет ячейку у логического строчного края. Для соседних закреплённых ячеек задайте каждой --uiify-table-sticky-offset.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

TableClient.ExpandTrigger / TableClient.ExpandedRow

СвойствоТипПо умолчаниюОписание
rowId*string—Общий ключ строки, связывающий кнопку раскрытия с нативным <tr>. Внутрь раскрытой строки поместите <td colSpan={columnCount}>.

TableClient.Root — @gunkin/uiify/components/table/client

СвойствоТипПо умолчаниюОписание
aria-labelstring—Доступное название таблицы, если нет видимой подписи или заголовка.
aria-labelledbystring—Идентификатор элемента, который подписывает таблицу.
selectionMode"none" | "single" | "multiple""none"Разрешён ли выбор строк и скольких одновременно; «none» формирует обычную статическую таблицу без роли grid.
selectionBehavior"toggle" | "replace"—Добавляет ли щелчок строку к выбору или заменяет текущий выбор.
defaultSelectedKeysIterable<string>—Изначально выбранные идентификаторы строк; выбор остаётся неуправляемым внутри компонента.
selectedKeysIterable<string>—Текущие выбранные идентификаторы строк; выбором управляет вызывающая сторона.
onSelectionChange(selectedKeys: Set<string>) => void—Вызывается с новым набором идентификаторов выбранных строк при каждом изменении выбора.
defaultSortDescriptorSortDescriptor | null—Начальные столбец и направление сортировки; состояние сортировки остаётся неуправляемым внутри компонента.
sortDescriptorSortDescriptor | null—Текущие столбец и направление сортировки; сортировка становится управляемой.
onSortChange(descriptor: SortDescriptor | null) => void—Вызывается с новым описателем сортировки или null при активации заголовка сортируемого столбца.
expandedKeys / defaultExpandedKeysIterable<string>—Управляемые или начальные ключи раскрытых строк.
onExpandedChange(keys: Set<string>) => void—Сообщает о запросах раскрытия. Управляемые строки ждут обновлённых ключей.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.Header

СвойствоТипПо умолчаниюОписание
stickybooleanfalseЗакрепляет секцию в контейнере прокрутки: Header — у начала блочной оси, Footer — у конца.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.Body

СвойствоТипПо умолчаниюОписание
childrenReactNode—Строки тела таблицы.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.Row

СвойствоТипПо умолчаниюОписание
id*string—Стабильный идентификатор строки, используемый как ключ выбора и идентификатор элемента.
disabledbooleanfalseЗапрещает выбор строки и получение фокуса с клавиатуры.
selectedboolean—Помечает строку выбранной в серверной разметке до того, как управление перейдёт хранилищу выбора.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.ColumnHeader

СвойствоТипПо умолчаниюОписание
id*string—Идентификатор столбца, на который ссылаются описатели сортировки.
allowsSortingbooleanfalseПозволяет заголовку переключать сортировку столбца и отражать её через aria-sort.
sortDirection"ascending" | "descending" | null—Направление сортировки столбца в начальной серверной разметке, если сортировка разрешена.
onClickReact.MouseEventHandler<HTMLTableCellElement>—Выполняется перед сортировкой; preventDefault() отменяет её изменение.
childrenReactNode—Подпись заголовка.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.Cell

СвойствоТипПо умолчаниюОписание
childrenReactNode—Содержимое ячейки.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.Caption

СвойствоТипПо умолчаниюОписание
childrenReactNode—Текст подписи, описывающей таблицу.
renderReactElement | ((props, state) => ReactElement)—Заменяет отображаемый элемент, сохраняя поведение и связи доступности.

Table.RowSelect

СвойствоТипПо умолчаниюОписание
rowId*string—Идентификатор строки, которую этот флажок выбирает и снимает с выбора.

Клавиатура

КлавишаДействие
TabПеревести фокус на элементы сортировки, выбора и раскрытия в TableClient
Enter / SpaceАктивировать кнопку сортировки или раскрытия в фокусе; переключить флажок
Arrow keysПеремещаться между доступными для выбора строками тела таблицы в TableClient

Доступность

По умолчанию Table формирует нативные <table>, <caption>, <thead>, <tbody> и <tfoot> без клиентского JavaScript; для семантики заголовков используйте ColumnHeader и RowHeader. Точка входа /client добавляет сортировку, выбор, навигацию по строкам с клавиатуры и управляемое раскрытие, отражённые в aria-sort, aria-expanded и aria-controls. ExpandedRow — нативный <tr>; поместите внутрь Cell с colSpan. Фильтрацией и порядком строк управляет потребитель.

Привязка стилей

data-uiify-tabledata-partdata-layoutdata-sizedata-variantdata-stickydata-selecteddata-disabled--uiify-table-sticky-offset
Эта страница переведена автоматически и ещё не проверена.