-
-
+
+
-
+
...
@@ -63,22 +63,20 @@ property `--fluent-data-grid-pinned-background`:
## Notes
-* Column resizing interacts correctly with sticky offsets — the JavaScript in
- `FluentDataGrid.razor.ts` recalculates `left` / `right` values after every resize step via
- `UpdatePinnedColumnOffsets`.
+* Column resizing keeps pinned columns aligned as widths change.
* Virtualization and paging are fully compatible because each rendered row's cells carry the
same `position: sticky` styling regardless of which page or scroll position is active.
-* In RTL layouts the browser interprets `left` / `right` according to the document direction, so
- pinned columns behave correctly without additional configuration.
+* RTL layouts are fully supported: start and end automatically map to the correct physical
+ direction based on the document's writing mode.
## Example
-Demonstrates pinned (frozen) columns using `Pin="DataGridColumnPin.Left"` and `Pin="DataGridColumnPin.Right"`.
+Demonstrates pinned (frozen) columns using `Pin="DataGridColumnPin.Start"` and `Pin="DataGridColumnPin.End"`.
The two leftmost columns and the Actions column remain visible while the rest scroll horizontally.
Wrap the grid in a `
` container and give the grid a `Style="min-width: max-content;"`
so that the horizontal scroll bar appears.
-Pinned columns require an explicit pixel `Width`.
+Pinned columns require an explicit `Width`.
{{ DataGridPinnedColumns }}
diff --git a/src/Core/Components/DataGrid/Columns/ColumnBase.razor.cs b/src/Core/Components/DataGrid/Columns/ColumnBase.razor.cs
index d5e53fa542..3a1441c6b1 100644
--- a/src/Core/Components/DataGrid/Columns/ColumnBase.razor.cs
+++ b/src/Core/Components/DataGrid/Columns/ColumnBase.razor.cs
@@ -188,21 +188,23 @@ public abstract partial class ColumnBase
public string? Width { get; set; }
///
- /// Gets or sets whether this column is pinned (frozen) to the left or right edge of the grid,
+ /// Gets or sets whether this column is pinned (frozen) to the start or end edge of the grid,
/// so it remains visible when the user scrolls horizontally.
- /// Pinned columns require an explicit in pixels (e.g., "150px").
- /// Left-pinned columns must be contiguous at the start of the column list;
- /// right-pinned columns must be contiguous at the end.
+ /// Pinned columns require an explicit .
+ /// Sticky offsets are recomputed from rendered header widths after the grid is rendered.
+ /// Start-pinned columns must be contiguous at the start of the column list;
+ /// end-pinned columns must be contiguous at the end.
///
[Parameter]
public DataGridColumnPin Pin { get; set; } = DataGridColumnPin.None;
///
- /// The sticky left or right CSS offset (in pixels) computed by
- /// when columns are collected.
+ /// The sticky start or end CSS offset seeded by
+ /// when columns are collected and later updated from
+ /// rendered widths by JavaScript.
/// Not intended for direct use by consumers.
///
- internal double PinOffsetPx { get; set; }
+ internal string PinOffset { get; set; } = "0px";
///
/// Gets or sets the minimal width of the column.
diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs
index e1fa32b112..bc8b596b84 100644
--- a/src/Core/Components/DataGrid/FluentDataGrid.razor.cs
+++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.cs
@@ -600,7 +600,7 @@ private void FinishCollectingColumns()
throw new ArgumentException("The 'HierarchicalToggle' parameter can only be set on the first column of the grid.");
}
- // Validate and compute offsets for pinned columns.
+ // Validate pinned columns and seed their initial sticky offsets.
ValidateAndComputePinnedColumns();
// Always re-evaluate after collecting columns when using displaymode grid. A column might be added or hidden and the _internalGridTemplateColumns needs to reflect that.
@@ -624,12 +624,13 @@ private void FinishCollectingColumns()
}
///
- /// Validates the pinned-column configuration and computes the sticky pixel offsets for each
- /// pinned column. Rules enforced:
+ /// Validates the pinned-column configuration and seeds initial sticky offsets for each
+ /// pinned column before JavaScript recomputes them from rendered widths after first render.
+ /// Rules enforced:
///
- /// - Pinned columns must specify an explicit pixel Width (e.g., "150px").
- /// - Left-pinned columns must be contiguous at the beginning of the column list.
- /// - Right-pinned columns must be contiguous at the end of the column list.
+ /// - Pinned columns must specify an explicit Width.
+ /// - Start-pinned columns must be contiguous at the beginning of the column list.
+ /// - End-pinned columns must be contiguous at the end of the column list.
///
///
private void ValidateAndComputePinnedColumns()
@@ -642,20 +643,20 @@ private void ValidateAndComputePinnedColumns()
ValidatePinnedColumnConstraints();
- // Compute left-pin sticky offsets (cumulative left-to-right).
- var leftOffset = 0.0;
- foreach (var col in _columns.Where(c => c.Pin == DataGridColumnPin.Left))
+ // Compute start-pin sticky offsets in display order.
+ var startOffset = 0.0;
+ foreach (var col in _columns.Where(c => c.Pin == DataGridColumnPin.Start))
{
- col.PinOffsetPx = leftOffset;
- leftOffset += ParsePixelWidth(col.Width);
+ col.PinOffset = $"{startOffset.ToString(CultureInfo.InvariantCulture)}px";
+ startOffset += ParsePixelWidth(col.Width);
}
- // Compute right-pin sticky offsets (cumulative right-to-left).
- var rightOffset = 0.0;
- foreach (var col in _columns.Where(c => c.Pin == DataGridColumnPin.Right).Reverse())
+ // Compute end-pin sticky offsets in reverse display order.
+ var endOffset = 0.0;
+ foreach (var col in _columns.Where(c => c.Pin == DataGridColumnPin.End).Reverse())
{
- col.PinOffsetPx = rightOffset;
- rightOffset += ParsePixelWidth(col.Width);
+ col.PinOffset = $"{endOffset.ToString(CultureInfo.InvariantCulture)}px";
+ endOffset += ParsePixelWidth(col.Width);
}
}
@@ -665,52 +666,46 @@ private void ValidateAndComputePinnedColumns()
///
private void ValidatePinnedColumnConstraints()
{
- // Width must be an explicit pixel value.
+ // Width must be explicitly provided for pinned columns.
foreach (var col in _columns.Where(c => c.Pin != DataGridColumnPin.None))
{
if (string.IsNullOrWhiteSpace(col.Width))
{
throw new ArgumentException(
$"Column '{col.Title ?? col.Index.ToString(CultureInfo.InvariantCulture)}' has Pin set but no Width. " +
- "Pinned columns require an explicit Width in pixels (e.g., '150px').");
- }
-
- if (!col.Width!.Trim().EndsWith("px", StringComparison.OrdinalIgnoreCase))
- {
- throw new ArgumentException(
- $"Column '{col.Title ?? col.Index.ToString(CultureInfo.InvariantCulture)}' has Pin set but Width '{col.Width}' is not in pixels. " +
- "Pinned columns require an explicit Width in pixels (e.g., '150px').");
+ "Pinned columns require an explicit Width.");
}
}
- // Left-pinned columns must be contiguous at the start: each one must be preceded by
- // another left-pinned column (or be the very first column).
+ // Start-pinned columns must be contiguous at the start: each one must be preceded by
+ // another start-pinned column (or be the very first column).
for (var i = 0; i < _columns.Count; i++)
{
- if (_columns[i].Pin == DataGridColumnPin.Left && i > 0 && _columns[i - 1].Pin != DataGridColumnPin.Left)
+ if (_columns[i].Pin == DataGridColumnPin.Start && i > 0 && _columns[i - 1].Pin != DataGridColumnPin.Start)
{
throw new ArgumentException(
- $"Column '{_columns[i].Title ?? _columns[i].Index.ToString(CultureInfo.InvariantCulture)}' is left-pinned but the preceding column is not. " +
- "Left-pinned columns must be contiguous at the start of the column list.");
+ $"Column '{_columns[i].Title ?? _columns[i].Index.ToString(CultureInfo.InvariantCulture)}' is start-pinned but the preceding column is not. " +
+ "Start-pinned columns must be contiguous at the start of the column list.");
}
}
- // Right-pinned columns must be contiguous at the end: each one must be followed by
- // another right-pinned column (or be the very last column).
+ // End-pinned columns must be contiguous at the end: each one must be followed by
+ // another end-pinned column (or be the very last column).
for (var i = 0; i < _columns.Count; i++)
{
- if (_columns[i].Pin == DataGridColumnPin.Right && i < _columns.Count - 1 && _columns[i + 1].Pin != DataGridColumnPin.Right)
+ if (_columns[i].Pin == DataGridColumnPin.End && i < _columns.Count - 1 && _columns[i + 1].Pin != DataGridColumnPin.End)
{
throw new ArgumentException(
- $"Column '{_columns[i].Title ?? _columns[i].Index.ToString(CultureInfo.InvariantCulture)}' is right-pinned but the following column is not. " +
- "Right-pinned columns must be contiguous at the end of the column list.");
+ $"Column '{_columns[i].Title ?? _columns[i].Index.ToString(CultureInfo.InvariantCulture)}' is end-pinned but the following column is not. " +
+ "End-pinned columns must be contiguous at the end of the column list.");
}
}
}
///
/// Parses a CSS pixel value string such as "150px" and returns the numeric value.
- /// Returns 0 if the string is null, empty, or not a valid pixel value.
+ /// Returns 0 if the string is null, empty, or not a valid pixel value so JavaScript
+ /// can recompute the final sticky offsets from rendered widths after first render.
///
private static double ParsePixelWidth(string? width)
{
@@ -1445,4 +1440,3 @@ private async Task ToggleExpandedAsync(TGridItem item)
}
}
}
-
diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.css b/src/Core/Components/DataGrid/FluentDataGrid.razor.css
index c86445a2bf..d03de008ea 100644
--- a/src/Core/Components/DataGrid/FluentDataGrid.razor.css
+++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.css
@@ -100,23 +100,23 @@
/* ---- Pinned (sticky) columns ---- */
/* Background: keeps content from showing through when scrolling. Override --fluent-data-grid-pinned-background to theme. */
-.fluent-data-grid th.col-pinned-left,
-.fluent-data-grid th.col-pinned-right {
+.fluent-data-grid th.col-pinned-start,
+.fluent-data-grid th.col-pinned-end {
background-color: var(--colorNeutralBackground1);
}
-.fluent-data-grid td.col-pinned-left,
-.fluent-data-grid td.col-pinned-right {
+.fluent-data-grid td.col-pinned-start,
+.fluent-data-grid td.col-pinned-end {
background-color: var(--fluent-data-grid-pinned-background);
}
-/* Visual separator on the trailing edge of the last left-pinned column */
-.fluent-data-grid td:nth-last-child(1 of .col-pinned-left) {
+/* Visual separator on the trailing edge of the last start-pinned column */
+.fluent-data-grid td:nth-last-child(1 of .col-pinned-start) {
border-inline-end: var(--strokeWidthThin) solid var(--colorNeutralStroke1);
}
-/* Visual separator on the leading edge of the first right-pinned column */
-.fluent-data-grid td:nth-child(1 of .col-pinned-right) {
+/* Visual separator on the leading edge of the first end-pinned column */
+.fluent-data-grid td:nth-child(1 of .col-pinned-end) {
border-inline-start: var(--strokeWidthThin) solid var(--colorNeutralStroke1);
}
@@ -124,13 +124,13 @@
For UseMenuService=false the inline z-index: 5 is absent, so we provide a floor here.
The sticky-header row needs the highest value to beat both the sticky-header row z-index (2)
and the pinned data cell z-index (1). */
-.fluent-data-grid th.col-pinned-left,
-.fluent-data-grid th.col-pinned-right {
+.fluent-data-grid th.col-pinned-start,
+.fluent-data-grid th.col-pinned-end {
z-index: 2;
}
-.fluent-data-grid tr[row-type='sticky-header'] > th.col-pinned-left,
-.fluent-data-grid tr[row-type='sticky-header'] > th.col-pinned-right {
+.fluent-data-grid tr[row-type='sticky-header'] > th.col-pinned-start,
+.fluent-data-grid tr[row-type='sticky-header'] > th.col-pinned-end {
background-color: var(--colorNeutralBackground4);
z-index: 4;
}
diff --git a/src/Core/Components/DataGrid/FluentDataGrid.razor.ts b/src/Core/Components/DataGrid/FluentDataGrid.razor.ts
index 2cb37b0ca9..f029e1290d 100644
--- a/src/Core/Components/DataGrid/FluentDataGrid.razor.ts
+++ b/src/Core/Components/DataGrid/FluentDataGrid.razor.ts
@@ -564,12 +564,13 @@ export namespace Microsoft.FluentUI.Blazor.DataGrid {
* pinned column so that columns stack correctly against the grid edge after the initial
* render or after a column is resized.
*
- * Left-pinned columns are processed left-to-right; each column's offset is the sum of
- * the widths of all left-pinned columns to its left.
- * Right-pinned columns are processed right-to-left; each column's offset is the sum of
- * the widths of all right-pinned columns to its right.
+ * Start-pinned columns are processed in DOM order; each column's offset is the sum of
+ * the widths of all start-pinned columns before it.
+ * End-pinned columns are processed in reverse DOM order; each column's offset is the sum of
+ * the widths of all end-pinned columns after it.
*
- * The function reads the actual rendered header-cell width so it handles both Grid mode
+ * The function reads the actual rendered header-cell width so it handles pinned columns whose
+ * configured widths use non-pixel CSS units as well as both Grid mode
* (CSS grid layout) and Table mode (standard table layout). Grid mode uses `offsetWidth`
* (includes borders, matches the grid-track width) while Table mode uses `clientWidth`
* (excludes borders, matches the CSS column width), consistent with how existing resize
@@ -592,7 +593,7 @@ export namespace Microsoft.FluentUI.Blazor.DataGrid {
* Applies a cumulative sticky offset to all cells in a column and returns the new
* running total to be used by the next column in the sequence.
*/
- function applyOffset(header: HTMLElement, offset: number, side: 'left' | 'right'): number {
+ function applyOffset(header: HTMLElement, offset: number, side: 'insetInlineStart' | 'insetInlineEnd'): number {
const colIndex = header.getAttribute('col-index');
if (!colIndex) { return offset; }
@@ -602,24 +603,24 @@ export namespace Microsoft.FluentUI.Blazor.DataGrid {
return offset + headerWidth(header);
}
- // Left-pinned columns: process in DOM (left-to-right) order.
- const leftPinnedHeaders = Array.from(
- gridElement.querySelectorAll('th.col-pinned-left')
+ // Start-pinned columns: process in DOM order.
+ const startPinnedHeaders = Array.from(
+ gridElement.querySelectorAll('th.col-pinned-start')
) as HTMLElement[];
- let leftOffset = 0;
- for (const header of leftPinnedHeaders) {
- leftOffset = applyOffset(header, leftOffset, 'left');
+ let startOffset = 0;
+ for (const header of startPinnedHeaders) {
+ startOffset = applyOffset(header, startOffset, 'insetInlineStart');
}
- // Right-pinned columns: process in reverse DOM (right-to-left) order.
- const rightPinnedHeaders = Array.from(
- gridElement.querySelectorAll('th.col-pinned-right')
+ // End-pinned columns: process in reverse DOM order.
+ const endPinnedHeaders = Array.from(
+ gridElement.querySelectorAll('th.col-pinned-end')
) as HTMLElement[];
- let rightOffset = 0;
- for (let i = rightPinnedHeaders.length - 1; i >= 0; i--) {
- rightOffset = applyOffset(rightPinnedHeaders[i], rightOffset, 'right');
+ let endOffset = 0;
+ for (let i = endPinnedHeaders.length - 1; i >= 0; i--) {
+ endOffset = applyOffset(endPinnedHeaders[i], endOffset, 'insetInlineEnd');
}
}
}
diff --git a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs
index 22b1173456..14dc98280a 100644
--- a/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs
+++ b/src/Core/Components/DataGrid/FluentDataGridCell.razor.cs
@@ -31,8 +31,8 @@ public FluentDataGridCell(LibraryConfiguration configuration) : base(configurati
.AddClass("column-header", when: CellType == DataGridCellType.ColumnHeader)
.AddClass("select-all", when: CellType == DataGridCellType.ColumnHeader && Column is SelectColumn)
.AddClass("multiline-text", when: Grid.MultiLine && (Grid.Items is not null || Grid.ItemsProvider is not null) && CellType != DataGridCellType.ColumnHeader)
- .AddClass("col-pinned-left", Column?.Pin == DataGridColumnPin.Left)
- .AddClass("col-pinned-right", Column?.Pin == DataGridColumnPin.Right)
+ .AddClass("col-pinned-start", Column?.Pin == DataGridColumnPin.Start)
+ .AddClass("col-pinned-end", Column?.Pin == DataGridColumnPin.End)
.AddClass(Owner.Class)
.Build();
@@ -50,8 +50,8 @@ public FluentDataGridCell(LibraryConfiguration configuration) : base(configurati
.AddStyle("height", "100%", Grid.MultiLine)
.AddStyle("min-height", "40px", Owner.RowType != DataGridRowType.Default)
.AddStyle("position", "sticky", Column != null && Column.Pin != DataGridColumnPin.None)
- .AddStyle("left", $"{(Column?.PinOffsetPx ?? 0).ToString(CultureInfo.InvariantCulture)}px", Column?.Pin == DataGridColumnPin.Left)
- .AddStyle("right", $"{(Column?.PinOffsetPx ?? 0).ToString(CultureInfo.InvariantCulture)}px", Column?.Pin == DataGridColumnPin.Right)
+ .AddStyle("inset-inline-start", Column?.PinOffset ?? "0px", Column?.Pin == DataGridColumnPin.Start)
+ .AddStyle("inset-inline-end", Column?.PinOffset ?? "0px", Column?.Pin == DataGridColumnPin.End)
.AddStyle("z-index", "1", Column != null && Column.Pin != DataGridColumnPin.None && CellType == DataGridCellType.Default)
.AddStyle(Owner.Style)
.Build();
diff --git a/src/Core/Enums/DataGridColumnPin.cs b/src/Core/Enums/DataGridColumnPin.cs
index 4aa90cf098..f666060c24 100644
--- a/src/Core/Enums/DataGridColumnPin.cs
+++ b/src/Core/Enums/DataGridColumnPin.cs
@@ -16,14 +16,14 @@ public enum DataGridColumnPin
None,
///
- /// The column is pinned to the left edge of the grid.
- /// The column will remain visible when the user scrolls right.
+ /// The column is pinned to the start edge of the grid.
+ /// The column will remain visible when the user scrolls toward the end.
///
- Left,
+ Start,
///
- /// The column is pinned to the right edge of the grid.
- /// The column will remain visible when the user scrolls left.
+ /// The column is pinned to the end edge of the grid.
+ /// The column will remain visible when the user scrolls toward the start.
///
- Right,
+ End,
}
diff --git a/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.FluentDataGrid_PinnedColumn_Snapshot.verified.razor.html b/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.FluentDataGrid_PinnedColumn_Snapshot.verified.razor.html
index 90d91a2865..656413b651 100644
--- a/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.FluentDataGrid_PinnedColumn_Snapshot.verified.razor.html
+++ b/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.FluentDataGrid_PinnedColumn_Snapshot.verified.razor.html
@@ -4,14 +4,14 @@
- |
+ |
|
-
+ |
|
-
+ |
Action
@@ -36,22 +36,22 @@
|
- | 1 |
- Denis Voituron |
+ 1 |
+ Denis Voituron |
Brussels |
- Edit |
+ Edit |
- | 2 |
- Vincent Baaij |
+ 2 |
+ Vincent Baaij |
Amsterdam |
- Edit |
+ Edit |
- | 3 |
- Bill Gates |
+ 3 |
+ Bill Gates |
Medina |
- Edit |
+ Edit |
diff --git a/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.razor b/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.razor
index 0435aeaaf5..301fd79076 100644
--- a/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.razor
+++ b/tests/Core/Components/DataGrid/FluentDataGridPinnedColumnTests.razor
@@ -31,43 +31,43 @@
}
// -------------------------------------------------------------------------
- // Single pinned-left column: correct CSS class and sticky style
+ // Single pinned-start column: correct CSS class and sticky style
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Left_Has_Sticky_Class_And_Style()
+ public void FluentDataGrid_PinnedColumn_Start_Has_Sticky_Class_And_Style()
{
// Arrange && Act
var cut = Render>(
@
-
+
);
- // Assert — every cell in the column carries col-pinned-left and position:sticky;left:0px
+ // Assert — every cell in the column carries col-pinned-start and a start offset of 0px
var cells = cut.FindAll("[col-index='1']");
Assert.NotEmpty(cells);
Assert.All(cells, cell =>
{
- Assert.Contains("col-pinned-left", cell.ClassName);
+ Assert.Contains("col-pinned-start", cell.ClassName);
Assert.Contains("position: sticky", cell.GetAttribute("style") ?? "");
- Assert.Contains("left: 0px", cell.GetAttribute("style") ?? "");
+ Assert.Contains("inset-inline-start: 0px", cell.GetAttribute("style") ?? "");
});
}
// -------------------------------------------------------------------------
- // Single pinned-right column: correct CSS class and sticky style
+ // Single pinned-end column: correct CSS class and sticky style
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Right_Has_Sticky_Class_And_Style()
+ public void FluentDataGrid_PinnedColumn_End_Has_Sticky_Class_And_Style()
{
// Arrange && Act
var cut = Render>(
@
-
+
);
@@ -75,9 +75,9 @@
Assert.NotEmpty(cells);
Assert.All(cells, cell =>
{
- Assert.Contains("col-pinned-right", cell.ClassName);
+ Assert.Contains("col-pinned-end", cell.ClassName);
Assert.Contains("position: sticky", cell.GetAttribute("style") ?? "");
- Assert.Contains("right: 0px", cell.GetAttribute("style") ?? "");
+ Assert.Contains("inset-inline-end: 0px", cell.GetAttribute("style") ?? "");
});
}
@@ -87,7 +87,7 @@
var cut = Render>(
@
-
+
);
@@ -97,53 +97,53 @@
}
// -------------------------------------------------------------------------
- // Two left-pinned columns: cumulative offsets
+ // Two start-pinned columns: cumulative offsets
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Left_Multiple_Cumulative_Offsets()
+ public void FluentDataGrid_PinnedColumn_Start_Multiple_Cumulative_Offsets()
{
- // Arrange && Act — col1: 100px, col2: 120px → col1 left:0px, col2 left:100px
+ // Arrange && Act — col1: 100px, col2: 120px → col1 start offset 0px, col2 start offset 100px
var cut = Render>(
@
-
-
+
+
);
Assert.All(cut.FindAll("[col-index='1']"), cell =>
- Assert.Contains("left: 0px", cell.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-start: 0px", cell.GetAttribute("style") ?? ""));
Assert.All(cut.FindAll("[col-index='2']"), cell =>
- Assert.Contains("left: 100px", cell.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-start: 100px", cell.GetAttribute("style") ?? ""));
}
// -------------------------------------------------------------------------
- // Two right-pinned columns: cumulative offsets
+ // Two end-pinned columns: cumulative offsets
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Right_Multiple_Cumulative_Offsets()
+ public void FluentDataGrid_PinnedColumn_End_Multiple_Cumulative_Offsets()
{
- // col1 (normal 1fr) | col2: 80px right-pinned | col3: 60px right-pinned
- // col3 (rightmost) → right:0px | col2 → right:60px
+ // col1 (normal 1fr) | col2: 80px end-pinned | col3: 60px end-pinned
+ // col3 (rightmost) → end offset 0px | col2 → end offset 60px
var cut = Render>(
@
-
-
+
+
);
- // col3 is index 3 — rightmost right-pinned → right: 0px
+ // col3 is index 3 — rightmost end-pinned → end offset 0px
Assert.All(cut.FindAll("[col-index='3']"), cell =>
- Assert.Contains("right: 0px", cell.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-end: 0px", cell.GetAttribute("style") ?? ""));
- // col2 is index 2 — next-to-last right-pinned → right: 60px (width of col3)
+ // col2 is index 2 — next-to-last end-pinned → end offset 60px (width of col3)
Assert.All(cut.FindAll("[col-index='2']"), cell =>
- Assert.Contains("right: 60px", cell.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-end: 60px", cell.GetAttribute("style") ?? ""));
}
// -------------------------------------------------------------------------
@@ -158,85 +158,91 @@
Render>(
@
-
+
);
});
}
// -------------------------------------------------------------------------
- // Pinned column with non-px Width throws
+ // Pinned column with non-px Width renders
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_With_NonPixel_Width_Throws()
+ public void FluentDataGrid_PinnedColumn_With_NonPixel_Width_Renders()
{
- Assert.Throws(() =>
+ var cut = Render>(
+ @
+
+
+
+ );
+
+ var cells = cut.FindAll("[col-index='1']");
+ Assert.NotEmpty(cells);
+ Assert.All(cells, cell =>
{
- Render>(
- @
-
-
-
- );
+ Assert.Contains("col-pinned-start", cell.ClassName);
+ Assert.Contains("position: sticky", cell.GetAttribute("style") ?? "");
+ Assert.Contains("inset-inline-start: 0px", cell.GetAttribute("style") ?? "");
});
}
// -------------------------------------------------------------------------
- // Ordering validation: isolated left-pinned column (not at the start) throws
+ // Ordering validation: isolated start-pinned column (not at the start) throws
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Left_Not_At_Start_Throws()
+ public void FluentDataGrid_PinnedColumn_Start_Not_At_Start_Throws()
{
- // col1 is unpinned, col2 is left-pinned → invalid
+ // col1 is unpinned, col2 is start-pinned → invalid
Assert.Throws(() =>
{
Render>(
@
-
+
);
});
}
// -------------------------------------------------------------------------
- // Ordering validation: left-pinned columns split by a normal column throws
+ // Ordering validation: start-pinned columns split by a normal column throws
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Left_NonContiguous_Throws()
+ public void FluentDataGrid_PinnedColumn_Start_NonContiguous_Throws()
{
- // col1 left-pinned, col2 normal, col3 left-pinned → not contiguous
+ // col1 start-pinned, col2 normal, col3 start-pinned → not contiguous
Assert.Throws(() =>
{
Render>(
@
-
+
-
+
);
});
}
// -------------------------------------------------------------------------
- // Ordering validation: isolated right-pinned column (not at the end) throws
+ // Ordering validation: isolated end-pinned column (not at the end) throws
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Right_Not_At_End_Throws()
+ public void FluentDataGrid_PinnedColumn_End_Not_At_End_Throws()
{
- // col1 right-pinned, col2 normal → invalid
+ // col1 end-pinned, col2 normal → invalid
Assert.Throws(() =>
{
Render>(
@
-
+
);
@@ -244,60 +250,60 @@
}
// -------------------------------------------------------------------------
- // Ordering validation: right-pinned columns split by a normal column throws
+ // Ordering validation: end-pinned columns split by a normal column throws
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_Right_NonContiguous_Throws()
+ public void FluentDataGrid_PinnedColumn_End_NonContiguous_Throws()
{
- // col1 normal, col2 right-pinned, col3 normal, col4 right-pinned → not contiguous
+ // col1 normal, col2 end-pinned, col3 normal, col4 end-pinned → not contiguous
Assert.Throws(() =>
{
Render>(
@
-
+
-
+
);
});
}
// -------------------------------------------------------------------------
- // Valid mixed layout: left-pinned + normal + right-pinned
+ // Valid mixed layout: start-pinned + normal + end-pinned
// -------------------------------------------------------------------------
[Fact]
- public void FluentDataGrid_PinnedColumn_LeftAndRight_Valid_Layout()
+ public void FluentDataGrid_PinnedColumn_StartAndEnd_Valid_Layout()
{
// Should not throw; verify offsets are correct
var cut = Render>(
@
-
-
+
+
-
+
);
- // col1 (Id) left-pinned → left: 0px
+ // col1 (Id) start-pinned → start offset 0px
Assert.All(cut.FindAll("[col-index='1']"), c =>
- Assert.Contains("left: 0px", c.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-start: 0px", c.GetAttribute("style") ?? ""));
- // col2 (Name) left-pinned → left: 50px
+ // col2 (Name) start-pinned → start offset 50px
Assert.All(cut.FindAll("[col-index='2']"), c =>
- Assert.Contains("left: 50px", c.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-start: 50px", c.GetAttribute("style") ?? ""));
// col3 (City) not pinned → no sticky style
Assert.All(cut.FindAll("[col-index='3']"), c =>
Assert.DoesNotContain("position: sticky", c.GetAttribute("style") ?? ""));
- // col4 (Action) right-pinned → right: 0px
+ // col4 (Action) end-pinned → end offset 0px
Assert.All(cut.FindAll("[col-index='4']"), c =>
- Assert.Contains("right: 0px", c.GetAttribute("style") ?? ""));
+ Assert.Contains("inset-inline-end: 0px", c.GetAttribute("style") ?? ""));
}
// -------------------------------------------------------------------------
@@ -310,10 +316,10 @@
var cut = Render>(
@
-
-
+
+
-
+
);