Forms

FormSummary

A read-only review of the values entered, in sections each with an Edit link, for the last step before sending.

#forms#record#list#no-js

Demo

Preview

Account

Edit
Name
Ada Lovelace
Email
ada@example.com
Newsletter
Yes

Plan

Edit
Plan
Team
Seats
4
Add-ons
Audit log, SSO
Coupon
—

Shipping

Address
1 Rue de Rivoli, 75001 Paris

Payment

Card
Visa ending 4242

Press Edit on a section.

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/form_summary.qwe
main.qwe
import ui/theme.qwe use theme_cssuse ui/form_summary.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>

Example

The code of the preview above.

demos/form_summary.qwe
component FormSummaryDemoLive() {    state editing = null    <div.demo-stack>        <FormSummary columns={1} on_edit={(k) => { editing = k }} sections={[            { title: "Shipping", key: "ship", items: [{ label: "Address", value: "1 Rue de Rivoli, 75001 Paris" }] },            { title: "Payment", key: "pay", items: [{ label: "Card", value: "Visa ending 4242" }] },        ]}/>        <p.demo-note>{editing == null ? "Press Edit on a section." : `on_edit got "${editing}".`}</p>    </div>}view FormSummaryDemo() =    <div.demo-stack>        <FormSummary sections={[            { title: "Account", href: "#account", items: [{ label: "Name", value: "Ada Lovelace" }, { label: "Email", value: "ada@example.com" },                                                           { label: "Newsletter", value: true }] },            { title: "Plan", href: "#plan", items: [{ label: "Plan", value: "Team" }, { label: "Seats", value: 4 },                                                     { label: "Add-ons", value: ["Audit log", "SSO"] }, { label: "Coupon", value: null }] },        ]}/>        <FormSummaryDemoLive/>    </div>

Source

ui/form_summary.qwe
// FormSummary: a read-only review of what was entered, in sections each with an// Edit link, for the last step of a sign-up or a checkout before it is sent.////   <FormSummary sections={[//       { title: "Account", href: "/signup/account", items: [{ label: "Name", value: "Ada" }, { label: "Email", value: "ada@example.com" }] },//       { title: "Plan", href: "/signup/plan", items: [{ label: "Plan", value: "Team" }, { label: "Seats", value: 4 }] },//   ]}/>//   <FormSummary items={[{ label: "Name", value: "Ada" }]} on_edit={(key) => { step = key }}/>//// sections: maps of { title, items, href?, key? }: href makes the Edit link; key// (the title by default) is what on_edit is given when there is no href. items:// one section's items, without a title. An item is { label, value }: a list is// written with commas, true and false as Yes and No, a number as it is, and null// or "" as empty ("—"). edit_label ("Edit"). columns: 1 (label above value) or// 2 (default, side by side where there is room). label: what screen readers call// the whole ("Summary").// on_edit(key): inside one of your components, called with the section's key// when its Edit button is pressed (sections with href are links instead).import ui/theme.qwe use ui_clslet form_summary_css = css`.ui-form-summary { display: grid; gap: 18px; min-width: 0; font: 14px/1.45 var(--ui-font); color: var(--ui-fg); }.ui-form-summary-section { display: grid; gap: 10px; }.ui-form-summary-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding-bottom: 8px; border-bottom: 1px solid var(--ui-border); }.ui-form-summary-title { margin: 0; font-size: 15px; font-weight: 600; }.ui-form-summary-edit {  padding: 0; border: 0; background: none; color: var(--ui-accent); font: 500 13px var(--ui-font); text-decoration: none;  cursor: pointer; border-radius: 3px;}.ui-form-summary-edit:hover { text-decoration: underline; }.ui-form-summary-edit:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-form-summary-list { display: grid; gap: 8px; margin: 0; }.ui-form-summary-item { display: grid; grid-template-columns: minmax(120px, 1fr) 2fr; gap: 4px 16px; margin: 0; }.ui-form-summary-one .ui-form-summary-item { grid-template-columns: 1fr; }.ui-form-summary-item dt { color: var(--ui-muted); }.ui-form-summary-item dd { margin: 0; overflow-wrap: anywhere; }.ui-form-summary-empty { color: var(--ui-muted); }@media (max-width: 480px) { .ui-form-summary-item { grid-template-columns: 1fr; } }`// A value as it is written in the summary.fn form_summary_text(v) -> str = match v {    null => ""    true => "Yes"    false => "No"    list as xs => xs | map((x) => form_summary_text(x)) | filter((s) => s != "") | join(", ")    _ => str(v)}view FormSummary(sections: list? = null, items: list = [], edit_label: str = "Edit", columns: int = 2,                 label: str = "Summary", on_edit = null, class: str? = null) {    style global form_summary_css    let parts = sections ?? [{ title: null, items: items }]    <div class={ui_cls(["ui-form-summary", columns == 1 && "ui-form-summary-one", class])} role="group" aria-label={label}>        {for [i, s] in enumerate(parts) => {            let key = s.key ?? s.title ?? str(i)            let edit = s.href != null                ? <a.ui-form-summary-edit href={s.href} aria-label={s.title != null ? `${edit_label} ${s.title}` : null}>{edit_label}</a>                : on_edit != null                    ? <button.ui-form-summary-edit type="button" aria-label={s.title != null ? `${edit_label} ${s.title}` : null}                              @click={() => { on_edit(key) }}>{edit_label}</button>                    : null            <section.ui-form-summary-section aria-label={s.title}>                {(s.title != null || edit != null) && <div.ui-form-summary-head>                    {s.title != null && <h3.ui-form-summary-title>{s.title}</h3>}                    {edit}                </div>}                <dl.ui-form-summary-list>                    {for it in s.items ?? [] => {                        let text = form_summary_text(it.value)                        <div.ui-form-summary-item>                            <dt>{it.label}</dt>                            <dd>{text != "" ? text : <span.ui-form-summary-empty aria-label="empty">—</span>}</dd>                        </div>                    }}                </dl>            </section>        }}    </div>}
Thread
57Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.