Skip to main content
twblazor
Home
  • Get started
  • Tailwind with Blazor
  • Why twblazor?
  • Theme
  • Class Merge
    • Configuring localization
    • RTL Provider
  • Breadcrumb
  • Card
  • Carousel
  • Collapse
  • DrawerNew
  • Footer
  • MenuNew
  • Navbar
  • On This PageNew
  • Sidebar
  • Stepper
  • Tabs
  • Tree List
  • Container
  • Flex
  • Grid
  • Button
  • FormNew
    • AutocompleteNew
    • Checkbox
    • Color Picker
    • Date Picker
    • Date Range Picker
    • Datetime Picker
    • Datetime Range Picker
    • File Upload
    • NumericNew
    • Radio Button
    • Range SliderNew
    • RatingNew
    • Select
    • Slider
    • Switch
    • Textfield
    • Time Picker
    • Time Range Picker
  • Alert
  • Avatar
  • Chip
  • Icon
  • PopoverNew
  • Progress
  • Skeleton
  • Spinner
  • Tooltip
  • Data Table
  • Pagination
  • Pick List
  • BarcodeNew
  • QR CodeNew
  • CalendarNew
  • Table
  • AttachmentNew
  • Overview
    • Bar
    • Bullet
    • Column
    • Dot Plot
    • Dumbbell
    • Icon
    • Lollipop
    • Radial Bar
    • Range
    • Word Cloud
    • Area
    • Bump
    • Bump Area
    • Candlestick
    • Gantt
    • Horizon
    • Line
    • Slope
    • Small Multiples
    • Stream Graph
    • Funnel
    • Gauge
    • Marimekko
    • Nightingale
    • Pie
    • Treemap
    • Waffle
    • Waterfall
    • Circular Treemap
    • Convex Treemap
    • Dendrogram
    • Sunburst
    • Barcode
    • Beeswarm
    • Box Plot
    • Density Plot
    • Histogram
    • Radial Histogram
    • Ridgeline
    • Strip Plot
    • Violin Plot
    • Categorical Scatter
    • Contour
    • Hexagonal Binning
    • Quadrant
    • Scatter
    • Heatmap
    • Matrix
    • Parallel Coordinates
    • Radar
    • Arc Diagram
    • Chord Diagram
    • Flowchart
    • Network Diagram
    • Sankey
    • Euler Diagram
    • Venn Diagram
  • Bubble
  • Marker
  • Message
  • Dialog Service
  • Toast Service
API DocumentationAI Agents & Skills
Home Get Started

Containers

TwGrid

TwGrid is a Blazor CSS grid component: responsive columns, columns that fit the space, spans, named areas, subgrid and alignment, with TwGridItem for placement.

Last updated 25 October 2026

Basic usage

Set Cols for equal columns, from 1 to 12, and Gap for the space between cells as a step on Tailwind's spacing scale, such as 4 for gap-4. Children fill the cells row by row.
  • Analytics

    Traffic and sales

  • Billing

    Invoices and plans

  • Calendar

    Meetings and events

  • Messages

    Team conversations

  • Storage

    Files and backups

  • Security

    Access and audits

RAZOR
<TwGrid Element="LayoutElement.Ul" Cols="2" ColsSm="3" Gap="3" AriaLabel="Apps">
    @foreach (var app in _apps)
    {
        <li class="rounded-xl bg-white p-4 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
            <span class="flex size-10 items-center justify-center rounded-lg bg-purple-50 text-lg text-purple-700 ring-1 ring-purple-600/10 dark:bg-purple-500/15 dark:text-purple-300 dark:ring-purple-400/20">
                <TwIcon Icon="@app.Icon" />
            </span>
            <p class="mt-3 font-semibold text-gray-900 dark:text-white">@app.Name</p>
            <p class="mt-0.5 text-sm text-gray-600 dark:text-gray-300">@app.Detail</p>
        </li>
    }
</TwGrid>
CSHARP
@code {
    private static readonly (string Name, string Detail, Icon Icon)[] _apps =
    [
        ("Analytics", "Traffic and sales", Icon.Bar_Chart_Line),
        ("Billing", "Invoices and plans", Icon.Credit_Card),
        ("Calendar", "Meetings and events", Icon.Calendar_Event),
        ("Messages", "Team conversations", Icon.Chat_Dots),
        ("Storage", "Files and backups", Icon.Cloud_Arrow_Up),
        ("Security", "Access and audits", Icon.Shield_Check)
    ];
}

Responsive columns

Add ColsSm, ColsMd, ColsLg, ColsXl or ColsXl2 to change the number of columns from that breakpoint up. These cards stack on a phone, sit two across from sm and four across from lg. Use Element="LayoutElement.Ul" for a list of things, so screen readers announce how many there are.
  • Headphones

    Noise cancelling, 30 hour battery

    £149.00

    In stock
  • Smartwatch

    Heart rate, GPS and sleep tracking

    £169.00

    In stock
  • Speaker

    Waterproof, 12 hour battery

    £59.99

    In stock
  • Keyboard

    Hot swappable switches

    £89.00

    In stock
RAZOR
<TwGrid Element="LayoutElement.Ul" Cols="1" ColsSm="2" ColsLg="4" Gap="4" AriaLabel="Products">
    @foreach (var product in _products)
    {
        <li>
            <TwCard Title="@product.Name" Class="h-full">
                <MediaContent>
                    <TwFlex Align="AlignItems.Center" Justify="JustifyContent.Center" Class="@($"aspect-4/3 bg-linear-to-br {product.Tone} text-5xl text-white")">
                        <TwIcon Icon="@product.Icon" />
                    </TwFlex>
                </MediaContent>
                <HeaderContent>
                    <p class="text-sm text-gray-600 dark:text-gray-300">@product.Detail</p>
                </HeaderContent>
                <FooterContent>
                    <p class="me-auto text-lg font-semibold tabular-nums text-gray-900 dark:text-white">@product.Price</p>
                    <TwChip Label="In stock" Color="Color.Success" Size="ChipSize.Small" StartIcon="Icon.Check_Lg" />
                </FooterContent>
            </TwCard>
        </li>
    }
</TwGrid>
CSHARP
@code {
    private sealed record Product(string Name, string Detail, string Price, Icon Icon, string Tone);
    
    private static readonly Product[] _products =
    [
        new("Headphones", "Noise cancelling, 30 hour battery", "£149.00", Icon.Headphones, "from-purple-600 to-indigo-700"),
        new("Smartwatch", "Heart rate, GPS and sleep tracking", "£169.00", Icon.Smartwatch, "from-fuchsia-700 to-purple-700"),
        new("Speaker", "Waterproof, 12 hour battery", "£59.99", Icon.Speaker, "from-indigo-600 to-sky-700"),
        new("Keyboard", "Hot swappable switches", "£89.00", Icon.Keyboard, "from-slate-600 to-slate-800")
    ];
}

Columns that fit the space

Set MinColWidth to a CSS length and the grid makes as many columns as fit, with no breakpoints, dropping to one column when even one does not fit. Columns stretch to fill the row; set AutoFill to keep empty columns instead, so a short row keeps the same widths.

MinColWidth="11rem"

PP

Priya Patel

Product designer

BO

Ben Okafor

Frontend engineer

CW

Chloe Williams

Researcher

DM

Dan Murphy

Data analyst

EC

Ella Chen

Engineering lead

MinColWidth="11rem" AutoFill

PP

Priya Patel

Product designer

BO

Ben Okafor

Frontend engineer

RAZOR
<TwFlex Direction="FlexDirection.Col" Gap="5">
    @foreach (var (label, fill, people) in _directories)
    {
        <div>
            <p class="mb-2 font-mono text-xs text-gray-600 dark:text-gray-400">@label</p>
            <TwGrid MinColWidth="11rem" AutoFill="fill" Gap="3">
                @foreach (var person in people)
                {
                    <TwFlex Align="AlignItems.Center" Gap="3" Class="rounded-xl bg-white p-3 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
                        <TwAvatar Name="@person.Name" Color="Color.Primary" Size="AvatarSize.Small" />
                        <TwFlexItem MinWidthZero>
                            <p class="truncate text-sm font-semibold text-gray-900 dark:text-white">@person.Name</p>
                            <p class="truncate text-xs text-gray-600 dark:text-gray-300">@person.Role</p>
                        </TwFlexItem>
                    </TwFlex>
                }
            </TwGrid>
        </div>
    }
</TwFlex>
CSHARP
@code {
    private sealed record Person(string Name, string Role);
    
    private static readonly Person[] _team =
    [
        new("Priya Patel", "Product designer"),
        new("Ben Okafor", "Frontend engineer"),
        new("Chloe Williams", "Researcher"),
        new("Dan Murphy", "Data analyst"),
        new("Ella Chen", "Engineering lead")
    ];
    
    private static readonly (string Label, bool Fill, Person[] People)[] _directories =
    [
        ("MinColWidth=\"11rem\"", false, _team),
        ("MinColWidth=\"11rem\" AutoFill", true, _team[..2])
    ];
}

Spanning columns and rows

Wrap a child in TwGridItem to place it. ColSpan and RowSpan stretch it across several tracks, and GridSpan.Full spans them all. Each has breakpoint variants, such as ColSpanMd, so this dashboard stacks on a phone and becomes a bento layout from md.
Revenue this month

£24,500

12.5% up on last month

Orders

1,234

8.2% up on last month

Customers

567

42 new this week

Returns

12

Down from 19

72%
RAZOR
<TwGrid Cols="1" ColsMd="4" Gap="4">
    <TwGridItem ColSpanMd="2" RowSpanMd="2" Class="rounded-2xl bg-linear-to-br from-purple-600 to-fuchsia-700 p-6 text-white shadow-lg shadow-purple-600/20">
        <TwFlex Direction="FlexDirection.Col" FullHeight Gap="2">
            <TwFlex Align="AlignItems.Center" Gap="2" Class="text-sm font-medium text-purple-50">
                <TwIcon Icon="Icon.Graph_Up_Arrow" />
                Revenue this month
            </TwFlex>
            <p class="text-4xl font-semibold tracking-tight tabular-nums">£24,500</p>
            <p class="text-sm text-purple-50">12.5% up on last month</p>
            <TwFlexItem PushEnd Class="pt-4">
                <TwFlex Align="AlignItems.End" Gap="1.5" Class="h-20" aria-hidden="true">
                    @foreach (var height in _revenueBars)
                    {
                        <TwFlexItem Flex="FlexSize.Fill" Class="rounded-t-md bg-white/70" Style="@($"height: {height}%")" />
                    }
                </TwFlex>
            </TwFlexItem>
        </TwFlex>
    </TwGridItem>
    @foreach (var stat in _stats)
    {
        <TwGridItem ColSpanMd="@stat.Span" Class="rounded-2xl bg-white p-5 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
            <TwFlex Align="AlignItems.Center" Justify="JustifyContent.Between" Gap="2">
                <p class="text-sm font-medium text-gray-600 dark:text-gray-300">@stat.Label</p>
                <TwIcon Icon="@stat.Icon" Class="text-lg text-purple-700 dark:text-purple-300" />
            </TwFlex>
            <p class="mt-2 text-2xl font-semibold tabular-nums text-gray-900 dark:text-white">@stat.Value</p>
            <p class="mt-1 text-xs text-gray-600 dark:text-gray-300">@stat.Note</p>
        </TwGridItem>
    }
    <TwGridItem ColSpan="GridSpan.Full" Class="rounded-2xl bg-white p-5 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
        <TwProgress T="int" Label="Quarterly target, 72% reached" Value="72" Max="100" Color="Color.Primary" />
    </TwGridItem>
</TwGrid>
CSHARP
@code {
    private static readonly int[] _revenueBars = [38, 52, 45, 63, 58, 72, 66, 84, 78, 95];
    
    private static readonly (string Label, string Value, string Note, Icon Icon, int Span)[] _stats =
    [
        ("Orders", "1,234", "8.2% up on last month", Icon.Bag, 2),
        ("Customers", "567", "42 new this week", Icon.People, 1),
        ("Returns", "12", "Down from 19", Icon.Arrow_Repeat, 1)
    ];
}

Start lines and offsets

Set ColStart to start an item on a given column line, leaving empty columns before it, and RowStart for a row line. Breakpoint variants such as ColStartLg move it only on wider screens. This sprint plan places each task on the day it starts. Moving an item away from its place in the markup changes only where it is drawn, so keep the markup in reading order.

Mon

Tue

Wed

Thu

Fri

Sat

Research 2 days
Design 3 days
Build 3 days
Launch 1 day
RAZOR
<div class="rounded-xl bg-white p-4 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
    <TwGrid Cols="6" ColGap="2" RowGap="2">
        @foreach (var day in _days)
        {
            <p class="border-b border-gray-200 pb-2 text-center text-xs font-semibold uppercase tracking-wide text-gray-600 dark:border-gray-700 dark:text-gray-300">@day</p>
        }
        @foreach (var task in _tasks)
        {
            <TwGridItem ColStart="task.Start" ColSpan="task.Days" Class="@($"rounded-lg px-2 py-2 text-xs font-medium text-white shadow-sm sm:px-3 sm:text-sm {task.Tone}")">
                @task.Name
                <span class="block text-xs font-normal text-white/90">@task.Days @(task.Days == 1 ? "day" : "days")</span>
            </TwGridItem>
        }
    </TwGrid>
</div>
CSHARP
@code {
    private static readonly string[] _days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
    
    private sealed record SprintTask(string Name, int Start, int Days, string Tone);
    
    private static readonly SprintTask[] _tasks =
    [
        new("Research", 1, 2, "bg-purple-600"),
        new("Design", 2, 3, "bg-fuchsia-700"),
        new("Build", 3, 3, "bg-indigo-600"),
        new("Launch", 6, 1, "bg-emerald-700")
    ];
}

Named areas

Set Areas to name the cells, one string per row with names separated by spaces, and place each TwGridItem with Area. A name repeated across cells makes one larger area; a full stop leaves a cell empty. Pair it with ColTemplate and RowTemplate to size the tracks. Areas are set inline, so they apply at every width.

Acme Studio

Search
  • Overview
  • Projects
  • Inbox
  • Settings

Overview

Visitors

8,240

Sign-ups

312

Revenue

£4.1k

All systems operational
RAZOR
<TwGrid Areas="_areas" ColTemplate="11rem 1fr" RowTemplate="auto 1fr auto" Class="h-80 overflow-hidden rounded-xl bg-white shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
    <TwGridItem Element="LayoutElement.Header" Area="header" Class="border-b border-gray-200 px-4 py-3 dark:border-gray-700">
        <TwFlex Align="AlignItems.Center" Gap="3">
            <span class="size-6 rounded-md bg-linear-to-br from-purple-600 to-fuchsia-700" aria-hidden="true"></span>
            <p class="font-semibold text-gray-900 dark:text-white">Acme Studio</p>
            <TwFlexItem PushEnd>
                <TwFlex Align="AlignItems.Center" Gap="2" Class="rounded-full bg-gray-100 px-3 py-1 text-xs text-gray-600 dark:bg-white/10 dark:text-gray-300">
                    <TwIcon Icon="Icon.Search" />
                    Search
                </TwFlex>
            </TwFlexItem>
        </TwFlex>
    </TwGridItem>
    <TwGridItem Element="LayoutElement.Nav" Area="sidebar" AriaLabel="Example sections" Class="border-e border-gray-200 bg-gray-50 p-3 dark:border-gray-700 dark:bg-white/5">
        <TwFlex Element="LayoutElement.Ul" Direction="FlexDirection.Col" Gap="1">
            @foreach (var (label, icon, current) in _sections)
            {
                <li>
                    <TwFlex Align="AlignItems.Center" Gap="2" Class="@($"rounded-md px-2 py-1.5 text-sm {(current ? "bg-purple-100 font-medium text-purple-800 dark:bg-purple-500/20 dark:text-purple-200" : "text-gray-700 dark:text-gray-300")}")">
                        <TwIcon Icon="icon" />
                        @label
                    </TwFlex>
                </li>
            }
        </TwFlex>
    </TwGridItem>
    <TwGridItem Area="main" Class="p-4">
        <p class="text-sm font-semibold text-gray-900 dark:text-white">Overview</p>
        <TwGrid Cols="1" ColsSm="3" Gap="3" Class="mt-3">
            @foreach (var (label, value) in _overview)
            {
                <div class="rounded-lg bg-gray-50 p-3 ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
                    <p class="text-xs text-gray-600 dark:text-gray-300">@label</p>
                    <p class="mt-1 font-semibold tabular-nums text-gray-900 dark:text-white">@value</p>
                </div>
            }
        </TwGrid>
    </TwGridItem>
    <TwGridItem Element="LayoutElement.Footer" Area="footer" Class="border-t border-gray-200 px-4 py-2 text-xs text-gray-600 dark:border-gray-700 dark:text-gray-300">
        All systems operational
    </TwGridItem>
</TwGrid>
CSHARP
@code {
    private static readonly string[] _areas = ["header header", "sidebar main", "sidebar footer"];
    
    private static readonly (string Label, Icon Icon, bool Current)[] _sections =
    [
        ("Overview", Icon.House, true),
        ("Projects", Icon.Kanban, false),
        ("Inbox", Icon.Inbox, false),
        ("Settings", Icon.Gear, false)
    ];
    
    private static readonly (string Label, string Value)[] _overview = [("Visitors", "8,240"), ("Sign-ups", "312"), ("Revenue", "£4.1k")];
}

Custom track templates

Set ColTemplate or RowTemplate to any CSS grid-template-columns or grid-template-rows value when equal tracks are not what you need, such as a label column sized to its longest label beside a flexible value column.

Order #1042

On its way
Placed
14 October 2026
Delivery address
12 High Street, Manchester, M1 1AA
Arriving
Friday, 9am to 1pm
Total
£248.00
RAZOR
<div class="max-w-md rounded-xl bg-white p-5 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
    <TwFlex Align="AlignItems.Center" Justify="JustifyContent.Between" Gap="3">
        <p class="font-semibold text-gray-900 dark:text-white">Order #1042</p>
        <TwChip Label="On its way" Color="Color.Info" Size="ChipSize.Small" StartIcon="Icon.Truck" />
    </TwFlex>
    <TwGrid Element="LayoutElement.Dl" ColTemplate="max-content 1fr" ColGap="6" RowGap="3" Class="mt-4 border-t border-gray-200 pt-4 text-sm dark:border-gray-700">
        <dt class="text-gray-600 dark:text-gray-300">Placed</dt>
        <dd class="font-medium text-gray-900 dark:text-white">14 October 2026</dd>
        <dt class="text-gray-600 dark:text-gray-300">Delivery address</dt>
        <dd class="font-medium text-gray-900 dark:text-white">12 High Street, Manchester, M1 1AA</dd>
        <dt class="text-gray-600 dark:text-gray-300">Arriving</dt>
        <dd class="font-medium text-gray-900 dark:text-white">Friday, 9am to 1pm</dd>
        <dt class="text-gray-600 dark:text-gray-300">Total</dt>
        <dd class="font-semibold tabular-nums text-gray-900 dark:text-white">£248.00</dd>
    </TwGrid>
</div>

Subgrid

Set SubgridRows on a grid nested in a grid item to line its rows up with the parent's, so the names, prices, descriptions and buttons of neighbouring cards line up however long each one is. SubgridCols does the same for columns.

Starter

£0 per month

Everything you need to try it out.

Team

Most popular

£12 per month

Shared workspaces, roles and permissions, audit history and single sign-on for growing teams.

Enterprise

£39 per month

Dedicated support and a service agreement.

RAZOR
<TwGrid Cols="1" ColsMd="3" ColGap="4" RowGap="8">
    @foreach (var plan in _plans)
    {
        <TwGridItem RowSpan="4" Element="LayoutElement.Article">
            <TwGrid SubgridRows RowGap="3" Class="@($"h-full rounded-2xl bg-white p-6 shadow-sm dark:bg-white/5 {(plan.Featured ? "ring-2 ring-purple-600 dark:ring-purple-400" : "ring-1 ring-gray-900/5 dark:ring-white/10")}")">
                <TwFlex Align="AlignItems.Center" Justify="JustifyContent.Between" Gap="2">
                    <h3 class="text-lg font-semibold text-gray-900 dark:text-white">@plan.Name</h3>
                    @if (plan.Featured)
                    {
                        <TwChip Label="Most popular" Color="Color.Primary" Size="ChipSize.Small" />
                    }
                </TwFlex>
                <p class="text-3xl font-semibold tracking-tight tabular-nums text-gray-900 dark:text-white">@plan.Price<span class="text-sm font-normal text-gray-600 dark:text-gray-300"> per month</span></p>
                <p class="text-sm text-gray-600 dark:text-gray-300">@plan.Text</p>
                <TwButton Label="Choose plan" AriaLabel="@($"Choose plan: {plan.Name}")" Color="Color.Primary" Variant="@(plan.Featured ? ButtonVariant.Filled : ButtonVariant.Outlined)" Class="self-end" />
            </TwGrid>
        </TwGridItem>
    }
</TwGrid>
CSHARP
@code {
    private sealed record Plan(string Name, string Price, string Text, bool Featured = false);
    
    private static readonly Plan[] _plans =
    [
        new("Starter", "£0", "Everything you need to try it out."),
        new("Team", "£12", "Shared workspaces, roles and permissions, audit history and single sign-on for growing teams.", true),
        new("Enterprise", "£39", "Dedicated support and a service agreement.")
    ];
}

Auto flow and dense packing

Set AutoFlow to Col to fill columns before rows; give the grid Rows and new columns are added as needed, sized by AutoCols. This shortcut sheet reads down each column. Dense fills earlier gaps with later, smaller items, as in the photo mosaic. Both change only where items are drawn, not the reading order.
Search
Ctrl + K
New file
Ctrl + N
Save
Ctrl + S
Undo
Ctrl + Z
Bold
Ctrl + B
Comment
Ctrl + /
  • Lake District
  • Snowdon
  • Brighton
  • Skye
  • Cornwall
  • Edinburgh
  • Bath
RAZOR
<TwFlex Direction="FlexDirection.Col" Gap="6">
    <TwGrid Element="LayoutElement.Dl" AutoFlow="GridAutoFlow.Col" Rows="3" AutoCols="GridAutoSize.Fr" ColGap="6" RowGap="2" Class="rounded-xl bg-white p-4 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
        @foreach (var (keys, action) in _shortcuts)
        {
            <TwFlex Align="AlignItems.Center" Justify="JustifyContent.Between" Gap="3" Class="text-sm">
                <dt class="text-gray-700 dark:text-gray-200">@action</dt>
                <dd><kbd class="rounded-md border border-gray-300 bg-gray-50 px-1.5 py-0.5 font-mono text-xs text-gray-800 dark:border-gray-600 dark:bg-white/10 dark:text-gray-100">@keys</kbd></dd>
            </TwFlex>
        }
    </TwGrid>
    <TwGrid Element="LayoutElement.Ul" AutoFlow="GridAutoFlow.Dense" Cols="4" Gap="3" AriaLabel="Photos">
        @foreach (var (photo, index) in _mosaic.Select((photo, index) => (photo, index)))
        {
            <TwGridItem Element="LayoutElement.Li" ColSpan="@(index % 3 == 0 ? 2 : 1)" Class="@($"flex h-24 items-end rounded-xl bg-linear-to-br p-3 text-sm font-medium text-white {photo.Tone}")">
                @photo.Name
            </TwGridItem>
        }
    </TwGrid>
</TwFlex>
CSHARP
@code {
    private static readonly (string Keys, string Action)[] _shortcuts =
    [
        ("Ctrl + K", "Search"),
        ("Ctrl + N", "New file"),
        ("Ctrl + S", "Save"),
        ("Ctrl + Z", "Undo"),
        ("Ctrl + B", "Bold"),
        ("Ctrl + /", "Comment")
    ];
    
    private static readonly (string Name, string Tone)[] _mosaic =
    [
        ("Lake District", "from-sky-700 to-indigo-700"),
        ("Snowdon", "from-emerald-700 to-teal-800"),
        ("Brighton", "from-purple-600 to-fuchsia-700"),
        ("Skye", "from-indigo-600 to-purple-800"),
        ("Cornwall", "from-teal-700 to-sky-800"),
        ("Edinburgh", "from-slate-600 to-slate-800"),
        ("Bath", "from-fuchsia-700 to-rose-800")
    ];
}

Aligning items in their cells

JustifyItems and Align align every item inside its cell, across and down. On a TwGridItem, JustifySelf and AlignSelf override them for one item. Justify and AlignContent space the tracks themselves when they are smaller than the grid.
Center Center
End, start
Stretch
Start, end
Center
RAZOR
<TwGrid Cols="3" AutoRows="GridAutoSize.Fr" JustifyItems="JustifyItems.Center" Align="AlignItems.Center" Gap="3" Class="h-56 rounded-xl bg-gray-50 bg-[radial-gradient(var(--color-gray-300)_1px,transparent_1px)] bg-size-[14px_14px] p-3 ring-1 ring-gray-900/5 dark:bg-gray-950/40 dark:bg-[radial-gradient(var(--color-gray-700)_1px,transparent_1px)] dark:ring-white/10">
    <span class="rounded-full bg-white px-3 py-1 text-sm font-medium text-gray-800 shadow-sm ring-1 ring-gray-900/10 dark:bg-gray-800 dark:text-gray-100 dark:ring-white/10">Center</span>
    <span class="rounded-full bg-white px-3 py-1 text-sm font-medium text-gray-800 shadow-sm ring-1 ring-gray-900/10 dark:bg-gray-800 dark:text-gray-100 dark:ring-white/10">Center</span>
    <TwGridItem JustifySelf="JustifySelf.End" AlignSelf="AlignSelf.Start" Class="rounded-full bg-purple-600 px-3 py-1 text-sm font-medium text-white shadow-sm">End, start</TwGridItem>
    <TwGridItem JustifySelf="JustifySelf.Stretch" Class="rounded-full bg-purple-600 px-3 py-1 text-center text-sm font-medium text-white shadow-sm">Stretch</TwGridItem>
    <TwGridItem JustifySelf="JustifySelf.Start" AlignSelf="AlignSelf.End" Class="rounded-full bg-purple-600 px-3 py-1 text-sm font-medium text-white shadow-sm">Start, end</TwGridItem>
    <span class="rounded-full bg-white px-3 py-1 text-sm font-medium text-gray-800 shadow-sm ring-1 ring-gray-900/10 dark:bg-gray-800 dark:text-gray-100 dark:ring-white/10">Center</span>
</TwGrid>

Equal height rows

Set AutoRows="GridAutoSize.Fr" to make every row as tall as the tallest, so cards in different rows line up too.
  • Set up in an afternoon.

    AJ

    Alice Johnson

    CTO, Northwind

  • The theme file meant our designers could restyle everything without touching a component.

    BO

    Ben Okafor

    Lead developer

  • Keyboard support out of the box saved us weeks of accessibility work, and the docs answered every question we had along the way.

    CW

    Chloe Williams

    Accessibility lead

  • Our dashboards finally look consistent.

    DM

    Dan Murphy

    Product manager

RAZOR
<TwGrid Element="LayoutElement.Ul" Cols="1" ColsSm="2" AutoRows="GridAutoSize.Fr" Gap="4" AriaLabel="Reviews">
    @foreach (var review in _reviews)
    {
        <li class="rounded-xl bg-white p-5 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
            <TwFlex Element="LayoutElement.Article" Direction="FlexDirection.Col" FullHeight Gap="4">
                <TwIcon Icon="Icon.Quote" Class="text-2xl text-purple-600 dark:text-purple-300" />
                <p class="text-sm text-gray-700 dark:text-gray-200">@review.Text</p>
                <TwFlexItem PushEnd>
                    <TwFlex Align="AlignItems.Center" Gap="3">
                        <TwAvatar Name="@review.Name" Size="AvatarSize.Small" />
                        <div>
                            <p class="text-sm font-semibold text-gray-900 dark:text-white">@review.Name</p>
                            <p class="text-xs text-gray-600 dark:text-gray-300">@review.Role</p>
                        </div>
                    </TwFlex>
                </TwFlexItem>
            </TwFlex>
        </li>
    }
</TwGrid>
CSHARP
@code {
    private sealed record Review(string Text, string Name, string Role);
    
    private static readonly Review[] _reviews =
    [
        new("Set up in an afternoon.", "Alice Johnson", "CTO, Northwind"),
        new("The theme file meant our designers could restyle everything without touching a component.", "Ben Okafor", "Lead developer"),
        new("Keyboard support out of the box saved us weeks of accessibility work, and the docs answered every question we had along the way.", "Chloe Williams", "Accessibility lead"),
        new("Our dashboards finally look consistent.", "Dan Murphy", "Product manager")
    ];
}

Visual order

Set Order on a TwGridItem to draw it in another position among items without a set place, from 1 to 12 or ItemOrder.First and ItemOrder.Last. The announcement is last in the markup, so screen readers reach it after the steps, but it is drawn first. As with every placement feature, screen readers and the Tab key still follow the markup.
1

Create your account

Sign up with your work email.

2

Verify your domain

Add one DNS record.

3

Invite your team

Send invites from settings.

New: invite your whole team in one step.
RAZOR
<TwGrid Cols="1" ColsMd="3" Gap="3">
    @foreach (var (number, title, text) in _onboarding)
    {
        <TwGridItem Class="rounded-xl bg-white p-4 shadow-sm ring-1 ring-gray-900/5 dark:bg-white/5 dark:ring-white/10">
            <span class="flex size-7 items-center justify-center rounded-full bg-purple-600 text-xs font-semibold text-white">@number</span>
            <p class="mt-3 font-semibold text-gray-900 dark:text-white">@title</p>
            <p class="mt-0.5 text-sm text-gray-600 dark:text-gray-300">@text</p>
        </TwGridItem>
    }
    <TwGridItem Order="ItemOrder.First" ColSpan="GridSpan.Full" Class="rounded-xl bg-linear-to-r from-purple-600 to-fuchsia-700 px-4 py-3 text-sm font-medium text-white">
        <TwFlex Align="AlignItems.Center" Gap="2">
            <TwIcon Icon="Icon.Megaphone" />
            New: invite your whole team in one step.
        </TwFlex>
    </TwGridItem>
</TwGrid>
CSHARP
@code {
    private static readonly (int Number, string Title, string Text)[] _onboarding =
    [
        (1, "Create your account", "Sign up with your work email."),
        (2, "Verify your domain", "Add one DNS record."),
        (3, "Invite your team", "Send invites from settings.")
    ];
}

Keyboard navigation

A grid layout is not interactive, so it has no keyboard controls of its own and is not a Tab stop. It is a visual layout, not a data grid, so it has no arrow key navigation. Tab moves through the controls inside it in the order they are written in the markup. Start lines, named areas, dense packing and Order change only where items are drawn, not the Tab order or what a screen reader reads first, so keep the markup in reading order.

Theme configuration

Styling is controlled by TwBlazorTheme.Components (a TwGridTheme), configured via the AddTwBlazor() options callback described on the Get Started page. Every property is a set of Tailwind classes, so changes are picked up by your own Tailwind build.
Property Type Controls
Base string
Inline string
AutoFit string
AutoFill string
Item string

Column and row counts, spans, start lines, auto flow and cell alignment come from the shared Grid utilities, written out at every breakpoint, and the gaps from Spacing, so any component theme can reuse them. Columns and spans go up to 12, rows and row spans up to 6, column start lines up to 13 and row start lines up to 7.

Full reference: TwGridTheme on the API docs.

On this page

  • Basic usage
  • Responsive columns
  • Columns that fit the space
  • Spanning columns and rows
  • Start lines and offsets
  • Named areas
  • Custom track templates
  • Subgrid
  • Auto flow and dense packing
  • Aligning items in their cells
  • Equal height rows
  • Visual order
  • Keyboard navigation
  • Theme configuration
twblazor

The Tailwind CSS component library for Blazor. Accessible, themeable and MIT licensed.

Discord (opens in a new tab) GitHub(opens in a new tab)

Get started

  • Install guide
  • Theming
  • Class merging
  • Localization

Guides

  • Tailwind CSS with Blazor
  • Why twblazor?
  • Right to left
  • AI agents and skills

Resources

  • API documentation (opens in a new tab)
  • llms.txt (opens in a new tab)
  • MIT License (opens in a new tab)

Community

  • Contributing (opens in a new tab)
  • Code of conduct (opens in a new tab)
  • Report an issue (opens in a new tab)

twblazor is and always will be free and open source.

An unhandled error has occurred. Reload