ee8797c142
Co-authored-by: Copilot <copilot@github.com>
178 lines
4.9 KiB
Markdown
178 lines
4.9 KiB
Markdown
# Alert
|
||
|
||
A contextual callout box for informational or error messages. Two variants: `default` (neutral) and `destructive` (red). An optional inline SVG icon is positioned automatically.
|
||
|
||
---
|
||
|
||
## HTML structure
|
||
|
||
```
|
||
div[role=alert].{variant classes}
|
||
{icon SVG} ← positioned absolute top-left via Tailwind arbitrary selectors
|
||
div
|
||
h5.font-medium ← title (always rendered)
|
||
div.text-sm ← description (omitted when empty)
|
||
```
|
||
|
||
---
|
||
|
||
## CSS mechanics
|
||
|
||
| Class / selector | Effect |
|
||
|---|---|
|
||
| `[&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4` | Positions any direct SVG child at top-left |
|
||
| `[&>svg~*]:pl-7` | Adds left padding to all siblings after the SVG so text is not covered by the icon |
|
||
| `[&>svg+div]:translate-y-[-3px]` | Vertically aligns the text div with the icon center |
|
||
| `border-destructive/50 text-destructive` | Red destructive variant |
|
||
|
||
The arbitrary selector approach (`[&>svg]:*`) means you can pass any SVG and it will be positioned correctly without extra wrapper divs.
|
||
|
||
---
|
||
|
||
## Constructor signature
|
||
|
||
```csharp
|
||
public Alert(
|
||
string title,
|
||
string description = "",
|
||
string variant = "default",
|
||
string icon = "")
|
||
```
|
||
|
||
| Parameter | Description |
|
||
|---|---|
|
||
| `title` | Required heading text |
|
||
| `description` | Optional body text below the title |
|
||
| `variant` | `"default"` or `"destructive"` |
|
||
| `icon` | Raw SVG string; omit for a text-only alert |
|
||
|
||
---
|
||
|
||
## Usage examples
|
||
|
||
### Informational (no icon)
|
||
|
||
```csharp
|
||
new Alert(
|
||
title: "Heads up",
|
||
description: "Your session expires in 5 minutes.")
|
||
```
|
||
|
||
### Destructive
|
||
|
||
```csharp
|
||
new Alert(
|
||
title: "Error",
|
||
description: "Invalid email or password.",
|
||
variant: "destructive")
|
||
```
|
||
|
||
### With an icon
|
||
|
||
```csharp
|
||
new Alert(
|
||
title: "New message",
|
||
description: "You have 3 unread messages.",
|
||
variant: "default",
|
||
icon: """
|
||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" viewBox="0 0 24 24"
|
||
fill="none" stroke="currentColor" stroke-width="2"
|
||
stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07
|
||
A19.5 19.5 0 013.07 9.77a19.79 19.79 0 01-3.07-8.67
|
||
A2 2 0 012 .18L5 0a2 2 0 012 1.72 ..."/>
|
||
</svg>
|
||
""")
|
||
```
|
||
|
||
### Title-only
|
||
|
||
```csharp
|
||
new Alert(title: "Changes saved successfully.", variant: "default")
|
||
```
|
||
|
||
---
|
||
|
||
## Tips and tricks
|
||
|
||
- The icon SVG should be `h-4 w-4` — larger sizes will push text out of alignment.
|
||
- For the `destructive` variant the icon automatically inherits `text-destructive` color via the variant class.
|
||
- The `description` slot is a raw HTML string — you can include `<a>` links or `<code>` spans.
|
||
- Use `Alert` inside a page's optional error slot rather than always rendering it — pass an empty byte array (`[]`) when there is no error so the slot renders nothing.
|
||
|
||
---
|
||
|
||
## Complete page example
|
||
|
||
**`Templates/SystemStatusPage.htmx`**
|
||
```html
|
||
<div class="max-w-2xl mx-auto py-10 space-y-4">
|
||
<h1 class="text-2xl font-bold mb-6">System Status</h1>
|
||
$$MaintenanceAlert$$
|
||
$$DatabaseAlert$$
|
||
$$ApiAlert$$
|
||
</div>
|
||
```
|
||
|
||
**`Templates/SystemStatusPage.htmx.cs`**
|
||
```csharp
|
||
namespace Htmx.ApiDemo.Templates;
|
||
|
||
public sealed class SystemStatusPage : SystemStatusPageBase
|
||
{
|
||
private readonly IHtmxComponent _maintenance;
|
||
private readonly IHtmxComponent _database;
|
||
private readonly IHtmxComponent _api;
|
||
|
||
public SystemStatusPage(bool maintenanceScheduled, bool dbDegraded, bool apiOk)
|
||
{
|
||
_maintenance = maintenanceScheduled
|
||
? new Components.Alert(
|
||
title: "Scheduled maintenance",
|
||
description: "The service will be unavailable on Saturday 00:00–02:00 UTC.",
|
||
variant: "default")
|
||
: HtmxEmpty.Instance;
|
||
|
||
_database = dbDegraded
|
||
? new Components.Alert(
|
||
title: "Database degraded",
|
||
description: "Query latency is elevated. Our team is investigating.",
|
||
variant: "destructive")
|
||
: HtmxEmpty.Instance;
|
||
|
||
_api = apiOk
|
||
? new Components.Alert(title: "All systems operational.")
|
||
: HtmxEmpty.Instance;
|
||
}
|
||
|
||
protected override void RenderMaintenanceAlert(HtmxRenderContext ctx)
|
||
=> _maintenance.Render(ctx.Next());
|
||
protected override void RenderDatabaseAlert(HtmxRenderContext ctx)
|
||
=> _database.Render(ctx.Next());
|
||
protected override void RenderApiAlert(HtmxRenderContext ctx)
|
||
=> _api.Render(ctx.Next());
|
||
}
|
||
```
|
||
|
||
**GET handler**
|
||
```csharp
|
||
[Handler]
|
||
[MapGet("/status")]
|
||
public static partial class GetSystemStatusHandler
|
||
{
|
||
public record Query();
|
||
|
||
private static Task<IResult> HandleAsync(
|
||
Query _,
|
||
HttpContext ctx,
|
||
CancellationToken ct)
|
||
{
|
||
var page = new SystemStatusPage(
|
||
maintenanceScheduled: true,
|
||
dbDegraded: false,
|
||
apiOk: true);
|
||
return ctx.WriteHtmxPage(page, title: "System Status");
|
||
}
|
||
}
|
||
```
|