Feedback

Alert

A message in the page in six tones and three variants, with an icon, announced to screen readers, and dismissable.

#feedback#status#no-js

Demo

Preview

A new version is out

Quillo 0.9 adds live queries. Read the notes.

Invoice sent

Northwind Traders got invoice INV-1042.
Maintenance on Sunday, 02:00 to 03:00 UTC.
Outline, accent.
Solid, success.

Placed straight in a page

DismissibleAlert hides itself when closed.

Get it

It needs theme.qwe, as every component does; or take the whole kit, quillo-ui.qwe. Each component brings its own styles to the pages that show it.

$ curl -O https://quillolang.org/components/ui/theme.qwe$ curl -O https://quillolang.org/components/ui/alert.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/alert.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/alert.qwe
component AlertDemoLive() {    state shown = true    <div.demo-stack>        {shown            ? <Alert tone="warning" title="Your trial ends in 3 days" dismissable={true}                     on_dismiss={() => { shown = false }}>Add a card to keep your projects.</Alert>            : <p.demo-note>Dismissed. <button type="button" @click={() => { shown = true }}>Show it again</button></p>}    </div>}view AlertDemo() =    <div.demo-stack>        <Alert title="A new version is out">Quillo 0.9 adds live queries. <a href="#alert">Read the notes</a>.</Alert>        <Alert tone="success" title="Invoice sent" id="alert-demo-sent">Northwind Traders got invoice INV-1042.</Alert>        <Alert tone="danger" title="Payment failed">The card ending in 4242 was declined.</Alert>        <Alert tone="neutral" icon={false}>Maintenance on Sunday, 02:00 to 03:00 UTC.</Alert>        <div.demo-row>            <Alert tone="accent" variant="outline">Outline, accent.</Alert>            <Alert tone="success" variant="solid">Solid, success.</Alert>            <Alert tone="danger" variant="solid">Solid, danger.</Alert>        </div>        <AlertDemoLive/>        <DismissibleAlert tone="info" title="Placed straight in a page">DismissibleAlert hides itself when closed.</DismissibleAlert>    </div>

Source

ui/alert.qwe
// Alert: a message in the flow of the page, with an icon for its tone.////   <Alert tone="success" title="Saved">Your changes are live.</Alert>//   <Alert tone="danger" variant="solid" title="Payment failed">The card was declined.</Alert>//   <DismissibleAlert tone="info" title="New: exports">Download any report as CSV.</DismissibleAlert>//// tone: "info" (default), "neutral", "accent", "success", "warning" or "danger".// Warning and danger are announced at once (role="alert"); the others politely// (role="status").// variant: "soft" (default), "outline" or "solid". title: a bold first line.// icon: false leaves the tone's icon out. id: the element's id.// dismissable shows a close button that calls on_dismiss(), inside one of your// components: <Alert dismissable={true} on_dismiss={() => { shown = false }}>.// DismissibleAlert takes the same props (but on_dismiss) and hides itself, so it// works placed straight in a page.import ui/theme.qwe use ui_clslet alert_css = css`.ui-alert-host { display: contents; }.ui-alert {  display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px;  border: 1px solid transparent; border-radius: var(--ui-radius-sm);  font: 14px/1.5 var(--ui-font); color: var(--ui-fg);  --t: var(--ui-info); --ts: var(--ui-info-soft);}.ui-alert-neutral { --t: var(--ui-muted); --ts: var(--ui-subtle); }.ui-alert-accent { --t: var(--ui-accent); --ts: var(--ui-accent-soft); }.ui-alert-success { --t: var(--ui-success); --ts: var(--ui-success-soft); }.ui-alert-warning { --t: var(--ui-warning); --ts: var(--ui-warning-soft); }.ui-alert-danger { --t: var(--ui-danger); --ts: var(--ui-danger-soft); }.ui-alert-soft { background: var(--ts); border-color: color-mix(in srgb, var(--t) 22%, transparent); }.ui-alert-outline { background: var(--ui-surface); border-color: color-mix(in srgb, var(--t) 55%, var(--ui-border)); }.ui-alert-solid { background: var(--t); color: var(--ui-bg); }.ui-alert-neutral.ui-alert-solid { background: var(--ui-fg); }.ui-alert-icon { flex: none; width: 20px; height: 20px; color: var(--t); }.ui-alert-solid .ui-alert-icon { color: inherit; }.ui-alert-body { flex: 1; min-width: 0; }.ui-alert-title { margin: 0; font-weight: 600; }.ui-alert a { color: inherit; font-weight: 500; text-underline-offset: 2px; }.ui-alert-text > :first-child { margin-top: 0; }.ui-alert-text > :last-child { margin-bottom: 0; }.ui-alert-title + .ui-alert-text { margin-top: 2px; color: color-mix(in srgb, currentColor 82%, transparent); }.ui-alert-x {  flex: none; display: grid; place-items: center; width: 26px; height: 26px; margin: -3px -5px -3px 0;  border: 0; border-radius: var(--ui-radius-sm); background: transparent; color: inherit;  font-size: 20px; line-height: 1; opacity: .7; cursor: pointer;}.ui-alert-x:hover { opacity: 1; background: color-mix(in srgb, currentColor 12%, transparent); }.ui-alert-x:focus-visible { outline: none; opacity: 1; box-shadow: var(--ui-focus); }`// The icon for each tone, drawn in currentColor.fn alert_icon(tone: str) {    let path = match tone {        "success" => <path d="M7 10.5l2 2 4-4.5"/>        "warning" => <path d="M10 7v4M10 14h.01"/>        "danger" => <path d="M7.5 7.5l5 5M12.5 7.5l-5 5"/>        _ => <path d="M10 9v5M10 6h.01"/>    }    let shape = tone == "warning"        ? <path d="M8.6 3.2L2.3 14.5a1.6 1.6 0 0 0 1.4 2.4h12.6a1.6 1.6 0 0 0 1.4-2.4L11.4 3.2a1.6 1.6 0 0 0-2.8 0z"/>        : <circle cx="10" cy="10" r="7.5"/>    <svg class="ui-alert-icon" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.7"         stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">{shape}{path}</svg>}view Alert(tone: str = "info", title: str? = null, variant: str = "soft", icon: bool = true,           dismissable: bool = false, on_dismiss = null, class: str? = null, id: str? = null, children) {    style global alert_css    <div class={ui_cls(["ui-alert", `ui-alert-${tone}`, `ui-alert-${variant}`, class])} id={id}         role={tone == "danger" || tone == "warning" ? "alert" : "status"}>        {icon && alert_icon(tone)}        <div.ui-alert-body>            {title != null && <p.ui-alert-title>{title}</p>}            <div.ui-alert-text>{children}</div>        </div>        {dismissable && <button.ui-alert-x type="button" aria-label="Dismiss"                                @click={() => { on_dismiss && on_dismiss() }}>×</button>}    </div>}component DismissibleAlert(tone: str = "info", title: str? = null, variant: str = "soft",                           icon: bool = true, class: str? = null, id: str? = null, children) {    style global alert_css    state shown = true    <div class="ui-alert-host">        {shown && <Alert tone={tone} title={title} variant={variant} icon={icon} class={class} id={id}                         dismissable={true} on_dismiss={() => { shown = false }}>{children}</Alert>}    </div>}
Thread
59Useful? Like it, or add to its thread below.

Thread 0 posts

On Alert: questions, tips, corrections, and code that uses it.

No posts yet. The first one opens the thread.