Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/BootstrapBlazor/BootstrapBlazor.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<Version>10.5.1-beta01</Version>
<Version>10.5.1-beta02</Version>
</PropertyGroup>

<ItemGroup>
Expand Down
6 changes: 3 additions & 3 deletions src/BootstrapBlazor/Components/Table/Table.razor
Original file line number Diff line number Diff line change
Expand Up @@ -1146,9 +1146,9 @@
RenderFragment<ColumnVisibleItem> RenderColumnListItem => item =>
@<div class="dropdown-item">
<Checkbox ShowAfterLabel="true" DisplayText="@item.DisplayName"
IsDisabled="@GetColumnsListState(item)"
@bind-Value="@item.Visible"
OnValueChanged="visible => OnToggleColumnVisible(item.Name, visible)">
IsDisabled="@GetColumnsListState(item)"
@bind-Value="@item.Visible"
OnValueChanged="visible => OnToggleColumnVisible(item.Name, visible)">
</Checkbox>
</div>;

Expand Down
65 changes: 50 additions & 15 deletions src/BootstrapBlazor/Components/Table/Table.razor.js
Original file line number Diff line number Diff line change
Expand Up @@ -536,24 +536,41 @@ const setExcelKeyboardListener = table => {
}

const resetTableWidth = table => {
const { options: { scrollWidth } } = table;
table.tables.forEach(t => {
const group = [...t.children].find(i => i.nodeName === 'COLGROUP')
if (group) {
let width = 0;
[...group.children].forEach(col => {
let colWidth = parseInt(col.style.width);
if (isNaN(colWidth)) {
colWidth = 100;
}
width += colWidth;
})
t.style.width = `${width}px`;
const colgroup = getLastColgroup(t, group);
if (colgroup) {
colgroup.style = null;
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

colgroup.style = null attempts to assign to the DOM style property (a read-only CSSStyleDeclaration in ES modules/strict mode) and can throw a TypeError. If the intent is to clear the last column's inline width, use colgroup.style.removeProperty('width'), set colgroup.style.width = '', or colgroup.removeAttribute('style') (depending on what needs to be cleared).

Suggested change
colgroup.style = null;
colgroup.style.width = '';

Copilot uses AI. Check for mistakes.
}
const width = getTableWidthByColumnGroup(t, 100);
if (width >= t.parentElement.offsetWidth + scrollWidth) {
t.style.width = `${width}px`;
}
else {
t.style.width = null;
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using t.style.width = null is unreliable because the setter coerces null to a string and may not remove the style (potentially leaving a stale width). Use t.style.removeProperty('width') (or set t.style.width = '') to explicitly clear the inline width when the table should auto-size to its container.

Suggested change
t.style.width = null;
t.style.removeProperty('width');

Copilot uses AI. Check for mistakes.
}

saveColumnWidth(table);
}
})
}

const getLastColgroup = (table, group) => {
const p = table.parentElement;
if (p) {
const length = group.children.length;
if (p.classList.contains("table-fixed-header")) {
return group.children[length - 2];
}
else {
return group.children[length - 1];
}
Comment on lines +560 to +569
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getLastColgroup returns a col element (a child of the COLGROUP), not a COLGROUP. The current name/variable (colgroup) is misleading and makes the logic harder to follow. Consider renaming to something like getLastColElement / getLastDataCol and renaming the local variable accordingly.

Copilot uses AI. Check for mistakes.
}
return null;
}

const setResizeListener = table => {
if (table.options.showColumnWidthTooltip) {
table.handlers.setResizeHandler = e => {
Expand Down Expand Up @@ -1047,15 +1064,33 @@ const saveColumnWidth = table => {
}));
}

const getTableWidthByColumnGroup = (table, defaultWidth) => {
return [...table.querySelectorAll('colgroup col')]
.map((col, index) => getColumnRenderWidth(table, col, index, defaultWidth))
.reduce((accumulator, val) => accumulator + val, 0);
}

const getColumnRenderWidth = (table, col, index, defaultWidth) => {
let width = parseFloat(col.style.width);
if (!isNaN(width) && width > 0) {
return width;
}

const header = table.querySelectorAll('thead > tr:last-child > th').item(index);
width = header?.offsetWidth ?? 0;
if (width > 0) {
return width;
}

const row = [...table.querySelectorAll('tbody > tr')].find(i => !i.classList.contains('is-detail'));
Comment on lines +1068 to +1085
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getTableWidthByColumnGroup/getColumnRenderWidth calls querySelectorAll for the header and searches tbody rows once per column, which scales poorly with many columns (O(n^2) DOM queries). Consider caching the header NodeList and the first non-detail row once per table-width calculation and passing them into getColumnRenderWidth to reduce repeated DOM work.

Suggested change
return [...table.querySelectorAll('colgroup col')]
.map((col, index) => getColumnRenderWidth(table, col, index, defaultWidth))
.reduce((accumulator, val) => accumulator + val, 0);
}
const getColumnRenderWidth = (table, col, index, defaultWidth) => {
let width = parseFloat(col.style.width);
if (!isNaN(width) && width > 0) {
return width;
}
const header = table.querySelectorAll('thead > tr:last-child > th').item(index);
width = header?.offsetWidth ?? 0;
if (width > 0) {
return width;
}
const row = [...table.querySelectorAll('tbody > tr')].find(i => !i.classList.contains('is-detail'));
const headers = table.querySelectorAll('thead > tr:last-child > th');
const rows = table.querySelectorAll('tbody > tr');
const row = [...rows].find(i => !i.classList.contains('is-detail'));
return [...table.querySelectorAll('colgroup col')]
.map((col, index) => getColumnRenderWidth(col, index, defaultWidth, headers, row))
.reduce((accumulator, val) => accumulator + val, 0);
}
const getColumnRenderWidth = (col, index, defaultWidth, headers, row) => {
let width = parseFloat(col.style.width);
if (!isNaN(width) && width > 0) {
return width;
}
const header = headers.item(index);
width = header?.offsetWidth ?? 0;
if (width > 0) {
return width;
}

Copilot uses AI. Check for mistakes.
width = row?.children.item(index)?.offsetWidth ?? 0;
return width > 0 ? width : defaultWidth;
}
Comment on lines +1067 to +1088
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (performance): Avoid repeated DOM queries inside width calculations for better performance.

getTableWidthByColumnGroup / getColumnRenderWidth re-run querySelectorAll on colgroup col, thead, and tbody for every column, which can be costly on large tables or during frequent resizes. Consider querying these once (e.g. const cols = ..., const headers = ..., a cached non-detail body row) and passing them into getColumnRenderWidth, or at least moving the header/body queries outside the per-column loop.

Suggested change
const getTableWidthByColumnGroup = (table, defaultWidth) => {
return [...table.querySelectorAll('colgroup col')]
.map((col, index) => getColumnRenderWidth(table, col, index, defaultWidth))
.reduce((accumulator, val) => accumulator + val, 0);
}
const getColumnRenderWidth = (table, col, index, defaultWidth) => {
let width = parseFloat(col.style.width);
if (!isNaN(width) && width > 0) {
return width;
}
const header = table.querySelectorAll('thead > tr:last-child > th').item(index);
width = header?.offsetWidth ?? 0;
if (width > 0) {
return width;
}
const row = [...table.querySelectorAll('tbody > tr')].find(i => !i.classList.contains('is-detail'));
width = row?.children.item(index)?.offsetWidth ?? 0;
return width > 0 ? width : defaultWidth;
}
const getTableWidthByColumnGroup = (table, defaultWidth) => {
const cols = [...table.querySelectorAll('colgroup col')];
const headers = table.querySelectorAll('thead > tr:last-child > th');
const bodyRows = table.querySelectorAll('tbody > tr');
const dataRow = [...bodyRows].find(row => !row.classList.contains('is-detail'));
return cols
.map((col, index) => getColumnRenderWidth(col, index, defaultWidth, headers, dataRow))
.reduce((accumulator, val) => accumulator + val, 0);
}
const getColumnRenderWidth = (col, index, defaultWidth, headers, dataRow) => {
let width = parseFloat(col.style.width);
if (!isNaN(width) && width > 0) {
return width;
}
const header = headers.item(index);
width = header?.offsetWidth ?? 0;
if (width > 0) {
return width;
}
const cell = dataRow?.children.item(index);
width = cell?.offsetWidth ?? 0;
return width > 0 ? width : defaultWidth;
}


const setTableDefaultWidth = table => {
if (table.tables.length > 0 && isVisible(table.tables[0])) {
const { scrollWidth, columnMinWidth } = table.options;
const tableWidth = [...table.tables[0].querySelectorAll('col')]
.map(i => {
const colWidth = parseFloat(i.style.width);
return isNaN(colWidth) ? columnMinWidth : colWidth;
})
.reduce((accumulator, val) => accumulator + val, 0);
const tableWidth = getTableWidthByColumnGroup(table.tables[0], columnMinWidth);

if (tableWidth > table.el.offsetWidth) {
table.tables[0].style.setProperty('width', `${tableWidth}px`);
Expand Down
Loading