Data

ComparisonTable

Features down the side and options across, with ticks, crosses and values in the cells, and one option picked out.

#data#table#commerce#no-js

Demo

Preview
FeatureFree$0RecommendedTeam$12 / user / monthBusinessTalk to us
Projects3UnlimitedUnlimited
MembersGuests are free1Up to 50Unlimited
Version historyNoYesYes
Single sign-onNoNoYes
Support
EmailWithin a dayYesYesYes
PhoneNoYes
FeatureVimEmacsVS Code
Modal editingYesNoNo
Written inCLispTypeScript
First release199119762015

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

Example

The code of the preview above.

demos/comparison_table.qwe
view ComparisonTableDemo() =    <div.demo-stack>        <ComparisonTable id="comparison-table-demo-plans" label="Plans compared" picked={1}                         options={[{ label: "Free", meta: "$0" }, { label: "Team", meta: "$12 / user / month" }, { label: "Business", meta: "Talk to us" }]}                         features={[                             { label: "Projects", values: ["3", "Unlimited", "Unlimited"] },                             { label: "Members", values: ["1", "Up to 50", "Unlimited"], hint: "Guests are free" },                             { label: "Version history", values: [false, true, true] },                             { label: "Single sign-on", values: [false, false, true] },                             { group: "Support" },                             { label: "Email", values: [true, true, true], hint: "Within a day" },                             { label: "Phone", values: [null, false, true] },                         ]}/>        <ComparisonTable id="comparison-table-demo-tools" label="Editors compared" options={["Vim", "Emacs", "VS Code"]}                         features={[                             { label: "Modal editing", values: [true, false, false] },                             { label: "Written in", values: ["C", "Lisp", "TypeScript"] },                             { label: "First release", values: ["1991", "1976", "2015"] },                         ]}/>    </div>

Source

ui/comparison_table.qwe
// ComparisonTable: features down the side, options across the top, and in each// cell a tick, a cross or a value: plans, products or tools side by side.////   <ComparisonTable label="Plans" options={["Free", "Team", "Business"]} picked={1}//                    features={[//                        { label: "Projects", values: ["3", "Unlimited", "Unlimited"] },//                        { label: "Single sign-on", values: [false, false, true] },//                        { group: "Support" },//                        { label: "Email", values: [true, true, true], hint: "Within a day" },//                    ]}/>//// options: the names across the top, strings or maps of { label, meta? } (meta: a// line under the name, "$12 / month"). features: rows of { label, values, hint? },// values one per option: true is a tick, false a cross, null a dash, anything else// its text; hint is a line under the feature's name. A row of only { group } is a// heading between features. picked: the index of the option picked out (its// column shaded and named with picked_label, "Recommended"). label: the table's// name for screen readers. id: the element's id. The first column stays in view// while it scrolls sideways on a narrow screen.import ui/theme.qwe use ui_clslet comparison_table_css = css`.ui-comparison { min-width: 0; overflow: auto; border: 1px solid var(--ui-border); border-radius: var(--ui-radius-sm);  background: var(--ui-surface); font: 14px/1.45 var(--ui-font); color: var(--ui-fg); }.ui-comparison table { width: 100%; border-collapse: separate; border-spacing: 0; }.ui-comparison th, .ui-comparison td { padding: 10px 14px; border-bottom: 1px solid var(--ui-border); vertical-align: top; }.ui-comparison td { text-align: center; }.ui-comparison thead th { text-align: center; background: var(--ui-subtle); font-weight: 600; }.ui-comparison thead th:first-child, .ui-comparison tbody th { position: sticky; left: 0; z-index: 1; text-align: left; font-weight: 500;  background: var(--ui-surface); }.ui-comparison thead th:first-child { background: var(--ui-subtle); }.ui-comparison tbody tr:last-child th, .ui-comparison tbody tr:last-child td { border-bottom: 0; }.ui-comparison-meta, .ui-comparison-hint { display: block; margin-top: 2px; color: var(--ui-muted); font-size: 12px; font-weight: 400; }.ui-comparison-group th { padding-top: 16px; background: var(--ui-surface); color: var(--ui-muted); font-size: 12px; font-weight: 600;  letter-spacing: .03em; text-transform: uppercase; }.ui-comparison-picked { background: color-mix(in srgb, var(--ui-accent-soft) 55%, var(--ui-surface)); }.ui-comparison thead th.ui-comparison-picked { background: var(--ui-accent-soft); color: var(--ui-accent); }.ui-comparison-tagline { display: block; margin-bottom: 4px; font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; }.ui-comparison-yes, .ui-comparison-no, .ui-comparison-none { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; vertical-align: middle; }.ui-comparison-yes { background: var(--ui-success-soft); color: var(--ui-success); }.ui-comparison-no { background: var(--ui-subtle); color: var(--ui-muted); }.ui-comparison-none { color: var(--ui-muted); }.ui-comparison-yes svg, .ui-comparison-no svg { width: 12px; height: 12px; }`// An option as { label, meta }.fn comparison_table_option(o) -> map = type_of(o) == "map" ? o : { label: str(o) }view ComparisonTable(options: list, features: list, picked: int? = null, picked_label: str = "Recommended",                     label: str? = null, id: str? = null, class: str? = null) {    style global comparison_table_css    let opts = options | map((o) => comparison_table_option(o))    <div class={ui_cls(["ui-comparison", class])} id={id}>        <table aria-label={label}>            <thead>                <tr>                    <th scope="col"><span.ui-sr>Feature</span></th>                    {for [i, o] in enumerate(opts) => <th scope="col" class={i == picked ? "ui-comparison-picked" : null}>                        {i == picked && <span.ui-comparison-tagline>{picked_label}</span>}                        {o.label}                        {o.meta != null && <span.ui-comparison-meta>{o.meta}</span>}                    </th>}                </tr>            </thead>            <tbody>                {for f in features => f.group != null                    ? <tr.ui-comparison-group><th scope="colgroup" colspan={str(len(opts) + 1)}>{f.group}</th></tr>                    : <tr>                        <th scope="row">{f.label}{f.hint != null && <span.ui-comparison-hint>{f.hint}</span>}</th>                        {for [i, v] in enumerate(opts) => {                            let val = (f.values ?? [])[i]                            <td class={i == picked ? "ui-comparison-picked" : null}>                                {val == true                                    ? <span.ui-comparison-yes><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2"                                          stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7"/></svg><span.ui-sr>Yes</span></span>                                    : val == false                                        ? <span.ui-comparison-no><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="2.2"                                              stroke-linecap="round" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8"/></svg><span.ui-sr>No</span></span>                                        : val == null                                            ? <span.ui-comparison-none aria-hidden="true">—</span>                                            : str(val)}                            </td>                        }}                    </tr>}            </tbody>        </table>    </div>}
Thread
56Useful? Like it, or add to its thread below.

Thread 0 posts

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

No posts yet. The first one opens the thread.