Button
A button, or a link that looks like one: four variants, three tones, three sizes, loading.
Demo
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/button.qwemain.qwe
import ui/theme.qwe use theme_cssuse ui/button.qweroute GET / = <html><head><style>{theme_css}</style></head><body class="ui-root">...</body></html>Example
The code of the preview above.
demos/button.qwe
view ButtonDemo() = <div.demo-stack> <div.demo-row> <Button id="button-demo-save">Save changes</Button> <Button variant="soft">Soft</Button> <Button variant="outline">Outline</Button> <Button variant="ghost">Ghost</Button> </div> <div.demo-row> <Button tone="neutral">Neutral</Button> <Button tone="danger">Delete</Button> <Button tone="danger" variant="soft">Discard</Button> <Button variant="outline" href="https://quillolang.org/docs/">A link</Button> </div> <div.demo-row> <Button size="sm">Small</Button> <Button size="lg">Large</Button> <Button loading={true}>Saving</Button> <Button disabled={true}>Disabled</Button> </div> </div>Source
ui/button.qwe
// Button: a button, or a link that looks like one.//// <Button>Save</Button>// <Button variant="outline" href="/docs">Read the docs</Button>// <Button tone="danger" type="submit" name="action" value="delete">Delete</Button>//// variant: "solid" (default), "soft", "outline" or "ghost".// tone: "accent" (default), "neutral" or "danger".// size: "sm", "md" (default) or "lg". full: as wide as its container.// href makes it an <a>; otherwise type ("button", "submit", "reset"), name, value// and disabled go to the <button>. loading shows a spinner and disables it.// id: the element's id, for a link to it or a test.// on_click(): inside one of your components, what a click does.import ui/theme.qwe use ui_clslet button_css = css`.ui-btn { display: inline-flex; align-items: center; justify-content: center; gap: .5em; height: 38px; padding: 0 16px; border: 1px solid transparent; border-radius: var(--ui-radius-sm); font: 500 14px/1 var(--ui-font); text-decoration: none; white-space: nowrap; cursor: pointer; transition: background .15s, border-color .15s, color .15s, box-shadow .15s; --b: var(--ui-accent); --bf: var(--ui-accent-fg); --bs: var(--ui-accent-soft);}.ui-btn:focus-visible { outline: none; box-shadow: var(--ui-focus); }.ui-btn[disabled], .ui-btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; pointer-events: none; }.ui-btn-neutral { --b: var(--ui-fg); --bf: var(--ui-bg); --bs: var(--ui-subtle); }.ui-btn-danger { --b: var(--ui-danger); --bf: #fff; --bs: var(--ui-danger-soft); }.ui-btn-solid { background: var(--b); color: var(--bf); }.ui-btn-solid:hover { background: color-mix(in srgb, var(--b) 88%, var(--ui-fg)); }.ui-btn-soft { background: var(--bs); color: var(--b); }.ui-btn-soft:hover { background: color-mix(in srgb, var(--bs) 80%, var(--b)); }.ui-btn-outline { background: transparent; color: var(--b); border-color: var(--ui-border); }.ui-btn-outline:hover { border-color: var(--b); background: var(--bs); }.ui-btn-ghost { background: transparent; color: var(--b); }.ui-btn-ghost:hover { background: var(--bs); }.ui-btn-sm { height: 30px; padding: 0 11px; font-size: 13px; }.ui-btn-lg { height: 46px; padding: 0 22px; font-size: 16px; }.ui-btn-full { display: flex; width: 100%; }.ui-btn-spin { width: 1em; height: 1em; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: ui-btn-spin .7s linear infinite; }@keyframes ui-btn-spin { to { transform: rotate(360deg); } }@media (prefers-reduced-motion: reduce) { .ui-btn-spin { animation-duration: 2s; } }`view Button(variant: str = "solid", tone: str = "accent", size: str = "md", href: str? = null, type: str = "button", name: str? = null, value: str? = null, disabled: bool = false, loading: bool = false, full: bool = false, label: str? = null, class: str? = null, id: str? = null, on_click = null, children) { style global button_css let cls = ui_cls(["ui-btn", `ui-btn-${variant}`, tone != "accent" && `ui-btn-${tone}`, size != "md" && `ui-btn-${size}`, full && "ui-btn-full", class]) let body = [loading && <span.ui-btn-spin aria-hidden="true"></span>, children] href != null ? <a class={cls} id={id} href={href} aria-label={label} aria-disabled={disabled ? "true" : null}>{body}</a> : <button class={cls} id={id} type={type} name={name} value={value} disabled={disabled || loading} aria-label={label} aria-busy={loading ? "true" : null} @click={() => { on_click && on_click() }}>{body}</button>}Related
BookmarkButtonA save-for-later toggle whose bookmark fills when pressed, with or without its label.8 views · 8 downloadsButtonGroupButtons joined edge to edge into one control, or spaced in a row; across or upright.6 views · 6 downloadsFabA round floating action button fixed to a corner of the screen, with an icon and an optional label.5 views · 7 downloadsFollowButtonFollow becomes Following once pressed, and says Unfollow on hover, as the social sites do.5 views · 7 downloadsIconButtonA square button with an icon, labelled for screen readers and on hover; built-in icons or your own.6 views · 9 downloadsLikeButtonA heart that toggles with a count that follows it, a real toggle for screen readers and forms.5 views · 4 downloads
Thread
Thread 0 posts
On Button: questions, tips, corrections, and code that uses it.
No posts yet. The first one opens the thread.