Задать вопрос
@Spike_zet

Как сделать скролл для body у таблицы?

Привет всем, мне нужно сделать таблицу с шапкой и боди, в таблице может быть сколько угодно колонок, жестко задавать количество колонок нельзя, ячейки не должны быть фиксированного размера, столбцы шапки и столбцы боди должны соответствовать друг другу, самое главное необходимо добавить вертикальный скролл на боди, что бы его можно было прокрутить. Так же шапка должна иметь поведение stiky. К сожалению не могу использовать библиотеки, т.к. нельзя попросту(

Вот такой код на данный момент имею, таблица выглядит как нужно, но скролл для боди у меня задать не получается.
<div
        className={cn(
          styles.wrapper,
          { [styles.whiteBlueMode]: whiteBlueMode },
          [className],
        )}
      >
        {HeaderContent}
        <div className={styles.tableContainer}>
          {tableTopRef && <div ref={tableTopRef} style={{ height: 0, width: '100%' }} />}
          <section className={styles.table} style={{ gridTemplateColumns }}>
            <div className={styles.header}>
              <div className={styles.headerRow}>
                {generatedColumns.map((column) => (
                  <div key={column.key} className={styles.column} style={getColumnWidthStyles(column)}>
                    <div className={styles.columnContent}>
                      {column.title}
                      {column.hasSorter && (
                        <SortButton
                          value={
                            sortModel?.field === column.key ? sortModel?.sort : null
                          }
                          onChange={(newValue) =>
                            handleSortChange({ sort: newValue, field: column.key })
                          }
                        />
                      )}
                    </div>
                  </div>
                ))}
              </div>
            </div>
            <div className={styles.body} style={{ overflowY: 'auto' }}>
              {currentData.map((row, rowIndex) => (
                <div
                  key={rowIndex}
                  className={cn(styles.row, { [styles.selected]: selectedRows.has(row.id) })}
                  ref={getRefForIndex?.(rowIndex, data.length)}
                >
                  {generatedColumns.map((column) => (
                    <div
                      key={column.key}
                      className={styles.cell}
                      role="button"
                      tabIndex={0}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter' || e.key === ' ') {
                          e.preventDefault();
                          column.onClick?.(row);
                        }
                      }}
                      onClick={(e) => {
                        e.stopPropagation();
                        column.onClick?.(row);
                      }}
                    >
                      {column.hasCheckbox && (
                        <Checkbox
                          checked={selectedRows.has(row.id)}
                          onChange={() => handleCheckboxChange(row.id)}
                          binaryCheckbox
                        />
                      )}
                      {column.icon && <Icon icon={column.icon} size={'sm'} />}
                      {column.render ? column.render(row, rowIndex) : row[column.key]}
                      {column.buttons && (
                        <div className={styles.buttons}>
                          {column.buttons.map((button, index) => (
                            <Button
                              key={index}
                              {...button}
                              onClick={(e) => {
                                e.stopPropagation();
                                button.onClick(row);
                              }}
                              link={button.link?.(row)}
                              size={button.size || 'm'}
                              mode={button.mode || 'icon'}
                            />
                          ))}
                        </div>
                      )}
                    </div>
                  ))}
                </div>
              ))}
              {loadMoreRef && <div ref={loadMoreRef} style={{ height: '20px' }} />}
            </div>
          </section>
        </div>


$header-background-color: var(--white);
$body-background-color: var(--white);

$row-background-color-hover: var(--abbey50);
$row-background-color-selected: var(--abbey50);
$row-background-color-selected-hover: var(--abbey100);

$border-color: var(--abbey100);

$header-color: var(--blue100);
$header-color-text: var(--abbey400);

$row-color-text: var(--abbey900);


.wrapper {
  display: flex;
  flex-direction: column;
  max-width: 100%;
  width: max-content;
  border: 1px solid $border-color;
  border-radius: 16px;
  padding: 24px;
  overflow: hidden;
  max-height: 100%;

  &.whiteBlueMode {
    border: none;
    padding: 0;
    border-radius: 0;
  }
}

.tableContainer {

  .table {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, max-content));
    overflow-x: auto;
    width: 100%;
    margin-bottom: 0;

    .header, .body {
      display: contents;
    }

    .headerRow, .row {
      display: contents;
    }

    .column, .cell {
      padding: 18px 16px;
      box-sizing: border-box;
    }

    .header {
      .headerRow {
        .column {
          position: sticky;
          top: 0;
          font: var(--font-s);
          background: $header-background-color;
          color: $header-color-text;
          font-weight: bold;
          z-index: 10;
          box-shadow: 0 1px 0 0 $border-color;

          &:first-of-type {
            border-top-left-radius: 16px;
          }

          &:last-of-type {
            border-top-right-radius: 16px;
          }

          .columnContent {
            display: flex;
            align-items: center;
            gap: 8px;
          }
        }
      }
    }

    .body {
      overflow-y: auto;

      .row {
        .cell {
          padding: 24px 16px;
          font: var(--font-m);
          font-weight: 400;
          color: $row-color-text;
          border-bottom: 1px solid $border-color;
          word-break: break-word;

          &:last-of-type {
            border-bottom-right-radius: 0;
            border-top-right-radius: 0;
          }

          .buttons {
            display: flex;
            gap: 8px;
          }
        }

        &:last-child .cell {
          border-bottom: none;
        }

        &.selected .cell {
          background: $row-background-color-selected;
        }

        &:hover .cell {
          background: $row-background-color-hover;
        }
      }
    }
  }
}

.wrapper.whiteBlueMode {
  .tableContainer {
    border-radius: 16px;
    border: 1px solid var(--abbey100);

    .headerRow .column {
      background-color: var(--blue100);
      padding-left: 32px;
      border: none;

      &:first-of-type {
        border-top-left-radius: 16px;
      }
    }

    .body .row {
      &:nth-child(even) .cell {
        background-color: var(--blue100);
      }

      .cell {
        padding-left: 32px;
        padding-right: 32px;
      }
    }
  }
}

.pagination {
  margin-top: 16px;
}

.footer {
  display: flex;
  justify-content: space-between;
  align-items: end;
  margin-top: 8px;
}

.noData {
  font: var(--font-m);
  text-align: center;
  font-weight: 400;
  padding: 8px;
  color: $row-color-text;
}
  • Вопрос задан
  • 111 просмотров
Подписаться 1 Простой 1 комментарий
Пригласить эксперта
Ответы на вопрос 2
Fragster
@Fragster
помогло? отметь решением!
Если есть возможность указать фон у thead и tbody, то эта задача решается не скроллом body, а position: sticky у thead и tfoot: https://play.tailwindcss.com/AFbTjPofBw (в примере фон полупрозрачный специально)
Ответ написан
Комментировать
NeiroNx
@NeiroNx
Программист
Чтобы сделать скролл - делают отдельно заголовок, отдельно тело в диве и скролят этот самый див.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы