M
Marai.UI
v1.0.0-alpha.7

Advanced Usage

Patterns for reusable styling, component composition, and complex layout scenarios.

Reusable Style Constants

When the same Tailwind utility string appears on multiple components, define it once as a C# constant in your page or a shared static class. This keeps strings literal (so Tailwind scans them) while eliminating repetition.

csharp
// In a shared file or at the top of your page @code block
private const string PrimaryBtn =
    "px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium " +
    "hover:bg-blue-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500";

private const string SecondaryBtn =
    "px-4 py-2 rounded-md border border-gray-300 text-sm font-medium " +
    "hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400";

private const string TextInput =
    "w-full rounded-md border border-gray-300 px-3 py-2 text-sm " +
    "focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent";
razor
<MButton Class="@PrimaryBtn">Save</MButton>
<MButton Class="@SecondaryBtn">Cancel</MButton>
<MInput Class="@TextInput" placeholder="Enter value" @bind-Value="name" />

Dialog with Form

Compose MDialog with EditForm to build modal data-entry flows. Use MDialogClose to wire a cancel button without manually tracking open state.

razor
<MDialog @bind-Open="isOpen">
    <MDialogContent Class="fixed inset-0 flex items-center justify-center z-50">
        <MDialogOverlay Class="absolute inset-0 bg-black/40" />
        <div class="relative z-10 w-full max-w-md rounded-xl bg-white p-6 shadow-xl">
            <MDialogTitle Class="text-lg font-semibold mb-4">Edit Profile</MDialogTitle>
            <EditForm Model="model" OnValidSubmit="HandleSubmit">
                <div class="flex flex-col gap-4">
                    <div>
                        <MLabel For="name" Class="block text-sm font-medium mb-1">Name</MLabel>
                        <MInput id="name" Class="w-full rounded border px-3 py-2 text-sm" @bind-Value="model.Name" />
                    </div>
                </div>
                <div class="mt-6 flex justify-end gap-3">
                    <MDialogClose Class="px-4 py-2 text-sm rounded border">Cancel</MDialogClose>
                    <MButton type="submit" Class="px-4 py-2 text-sm rounded bg-blue-600 text-white">Save</MButton>
                </div>
            </EditForm>
        </div>
    </MDialogContent>
</MDialog>

Tabs with Dynamic Content

MTabs manages the active panel index via @bind-ActiveIndex. Pair with a @switch or conditional render inside MTabsContent to show different views per tab.

razor
<MTabs @bind-ActiveIndex="activeTab">
    <MTabsList Class="flex border-b border-gray-200 mb-4">
        <MTabsTrigger Index="0" Class="px-4 py-2 text-sm font-medium data-[state=active]:border-b-2 data-[state=active]:border-blue-600">Overview</MTabsTrigger>
        <MTabsTrigger Index="1" Class="px-4 py-2 text-sm font-medium data-[state=active]:border-b-2 data-[state=active]:border-blue-600">Settings</MTabsTrigger>
    </MTabsList>
    <MTabsContent Index="0">
        @if (activeTab == 0) { <p>Overview content here.</p> }
    </MTabsContent>
    <MTabsContent Index="1">
        @if (activeTab == 1) { <p>Settings content here.</p> }
    </MTabsContent>
</MTabs>

@code {
    private int activeTab = 0;
}

Card Layout for Forms

Use MCard sections to visually group form fields. Combine MLabel, MInput, and MButton for a consistent form layout without any external CSS.

razor
<MCard Class="w-full max-w-md rounded-xl border border-gray-200 shadow-sm">
    <MCardHeader Class="px-6 pt-6 pb-4 border-b border-gray-100">
        <h2 class="text-base font-semibold">Account Details</h2>
    </MCardHeader>
    <MCardContent Class="px-6 py-5 flex flex-col gap-4">
        <div>
            <MLabel For="email" Class="block text-sm font-medium text-gray-700 mb-1">Email</MLabel>
            <MInput id="email" type="email" Class="w-full rounded-md border px-3 py-2 text-sm" @bind-Value="email" />
        </div>
        <div>
            <MLabel For="pwd" Class="block text-sm font-medium text-gray-700 mb-1">Password</MLabel>
            <MInput id="pwd" type="password" Class="w-full rounded-md border px-3 py-2 text-sm" @bind-Value="password" />
        </div>
    </MCardContent>
    <MCardFooter Class="px-6 pb-6 flex justify-end">
        <MButton Class="px-4 py-2 rounded-md bg-blue-600 text-white text-sm font-medium hover:bg-blue-700">Update</MButton>
    </MCardFooter>
</MCard>

@code {
    private string email = string.Empty;
    private string password = string.Empty;
}

MDropdown accepts any content in its trigger slot. Pass an avatar, icon button, or badge as the trigger instead of a plain text button.

razor
<MDropdown>
    <MDropdownTrigger>
        <MAvatar Src="https://example.com/avatar.jpg" Class="w-8 h-8 rounded-full cursor-pointer" />
    </MDropdownTrigger>
    <MDropdownContent Class="absolute right-0 mt-1 w-48 rounded-lg border border-gray-200 bg-white shadow-lg py-1 z-50">
        <MDropdownItem Class="px-4 py-2 text-sm hover:bg-gray-50 cursor-pointer">Profile</MDropdownItem>
        <MDropdownItem Class="px-4 py-2 text-sm hover:bg-gray-50 cursor-pointer">Settings</MDropdownItem>
        <MSeparator Class="my-1" />
        <MDropdownItem Class="px-4 py-2 text-sm text-red-600 hover:bg-red-50 cursor-pointer">Sign out</MDropdownItem>
    </MDropdownContent>
</MDropdown>

Styled DataTable

Use TableClass, HeaderClass, and per-column CellClass on MDataTableColumn to apply a consistent table style without wrapper divs.

razor
<MDataTable Items="users" PageSize="10"
    TableClass="w-full text-sm border-collapse"
    HeaderClass="bg-gray-50 text-xs font-semibold text-gray-500 uppercase tracking-wide">
    <MDataTableColumn Title="Name" Property="u => u.Name"
        CellClass="px-4 py-3 font-medium text-gray-900" />
    <MDataTableColumn Title="Email" Property="u => u.Email"
        CellClass="px-4 py-3 text-gray-600" />
    <MDataTableColumn Title="Role" Property="u => u.Role"
        CellClass="px-4 py-3 text-gray-600" />
</MDataTable>