Reordering
Since 0.1.0-alpha.20Static server-side rendering: no circuit, no WebAssembly.
Every move can be made three ways: by dragging, from a menu of moves, or with Alt+arrow keys. The menu also works with JavaScript off, where each move posts the form. To move items between lists, such as the columns of a board, put the lists in a DropZoneGroup.
Reordering, and saving the order
A reorderable list gives each item a drag handle with a menu of moves. Set Reorderable. On static pages, give the list a Name and pass the posted ListOrder back as Order; Order.Arrange puts your items in the posted order. On interactive pages, bind @bind-Items to keep the new order.
Preview
Code
@* On a static page the list posts with its form: Order holds the posted keys and any menu move,
and the list shows them. Save arranges the steps when the form's own button posted. *@
<Stack Gap="3" MaxWidth="24.Rem" Grow>
<Form Model="this" FormName="list-view-steps" OnValidSubmit="Save">
<ListView @bind-Items="_steps" ItemKey="s => s.Id" ItemText="s => s.Title" Reorderable Name="order" Order="Order" Bordered />
<FormActions><Button Submit>Save order</Button></FormActions>
</Form>
if (_saved is not null)
{
<TextBlock Size="TextSize.Sm" Color="Color.Muted">_saved</TextBlock>
}
</Stack>
{
[SupplyParameterFromForm(FormName = "list-view-steps", Name = "order")]
private ListOrder? Order { get; set; }
private IReadOnlyList<Step> _steps = [new("1", "Draft"), new("2", "Review"), new("3", "Approve"), new("4", "Publish")];
private string? _saved;
private void Save()
{
// A menu move posts too; only the Save button saves.
if (Order?.Move is not null)
{
return;
}
if (Order is not null)
{
_steps = Order.Arrange(_steps, s => s.Id);
}
_saved = $"Saved: {string.Join(", ", _steps.Select(s => s.Title))}.";
}
}Static: Drag a handle, or use its menu or Alt+arrow keys. Items move on the page and the move is announced. Save order posts the new order.
Dragging the whole item
To let a drag start anywhere on an item, such as a card, set DragWholeItem. With a mouse, the drag starts after a small move; on touch, after a long press, so a swipe still scrolls the page. Links, buttons and fields inside the item still work. If the list has an ItemMenu, there are no handles: each ⋯ menu ends with a Move submenu, and Alt+arrow keys work on the ⋯ button.
Preview
Code
@* DragWholeItem: each card drags from anywhere on it, with a mouse after a small move and on touch
after a long press, so a swipe still scrolls. With an ItemMenu there are no handles: each card's
⋯ menu ends with Move, a submenu of Move up, Move down, Move to top and Move to bottom. Open stands in for
a link to the tile's report: here it names the tile under the list. *@
NavigationManager Navigation
<Stack Gap="3" Grow>
<Form Model="this" FormName="list-view-tiles" OnValidSubmit="Save">
<ListView @bind-Items="_tiles" ItemKey="t => t.Id" ItemLabel="t => t.Title" Reorderable DragWholeItem Name="tiles" Order="Order"
Columns="3" Bordered Context="tile">
<ChildContent>
<Stack Gap="1">
<Heading Level="3" Size="TextSize.Md">tile.Title</Heading>
<TextBlock Size="TextSize.Sm" Color="Color.Muted">tile.Description</TextBlock>
</Stack>
</ChildContent>
<ItemMenu>
<MenuItem Href="Navigation.GetUriWithQueryParameter("tile", tile.Id)" Icon="Lucide.ExternalLink">Open</MenuItem>
</ItemMenu>
</ListView>
<FormActions><Button Submit>Save layout</Button></FormActions>
</Form>
if (Opened is not null && _tiles.FirstOrDefault(t => t.Id == Opened) is { } open)
{
<TextBlock Size="TextSize.Sm" Color="Color.Muted">Opened: open.Title.</TextBlock>
}
if (_saved is not null)
{
<TextBlock Size="TextSize.Sm" Color="Color.Muted">_saved</TextBlock>
}
</Stack>
{
[SupplyParameterFromQuery(Name = "tile")] private string? Opened { get; set; }
[SupplyParameterFromForm(FormName = "list-view-tiles", Name = "tiles")]
private ListOrder? Order { get; set; }
private IReadOnlyList<Tile> _tiles =
[
new("sales", "Sales", "Revenue this month against last."),
new("orders", "Orders", "Open, shipped and returned."),
new("traffic", "Traffic", "Visitors by source."),
new("stock", "Stock", "Items running low."),
new("support", "Support", "Tickets waiting for a reply."),
new("team", "Team", "Who's in today."),
];
private string? _saved;
private void Save()
{
// A menu move posts too; only the Save button saves.
if (Order?.Move is not null)
{
return;
}
if (Order is not null)
{
_tiles = Order.Arrange(_tiles, t => t.Id);
}
_saved = $"Saved: {string.Join(", ", _tiles.Select(t => t.Title))}.";
}
}Static: Drag a card, or press and hold one on a phone; the other cards move aside to show where it will land. Move in its ⋯ menu and Alt+arrow keys on the ⋯ button move it too. Save layout posts the new order.