Actions

Button

One clear action: primary, quiet, ghost or danger. A link with href, a form button without.

openvibe-shared/kitJSON

Build it

kit.button({ label: 'Go live', href: '/go', icon: 'live' }) + kit.button({ label: 'Not now', kind: 'quiet', type: 'button' }) + kit.button({ label: 'Delete', kind: 'danger', type: 'button', small: true })

Props

href
any?
icon
string?
kind
string?
name
any?
type
string?
attrs
any?
label
string?
small
boolean?
value
any?

Anatomy

  • containerbackground color.accent.strong; radius radius.pill; minHeight size.tap; paddingX space.lg
  • labelcolor color.accent.onStrong; size type.size.body; weight type.weight.bold
  • iconsize size.icon; color color.accent.onStrong

Behaviour and access

Keyboard
Standard focus order
Outside tap
Leaves it open
Scroll
The page still scrolls
Reduced motion
Remove movement; keep the state change.
Name
its label
Target
44 × 44 on touch
Focus
Enter (and Space as a button)

States

  • default
  • hover
  • pressed
  • focused
  • disabled

Tokens

  • color.accent.strong
  • radius.pill
  • size.tap
  • space.lg
  • color.accent.onStrong
  • type.size.body
  • type.weight.bold
  • size.icon

Android · Jetpack Compose

Button

@Composable fun OvButton(label: String, onClick: () -> Unit, kind: OvKind = OvKind.Primary, icon: ImageVector? = null) { val c = MaterialTheme.colorScheme val colors = when (kind) { OvKind.Primary -> ButtonDefaults.buttonColors(containerColor = c.primaryContainer, contentColor = c.onPrimaryContainer) OvKind.Danger -> ButtonDefaults.buttonColors(containerColor = c.error, contentColor = c.onError) OvKind.Quiet -> ButtonDefaults.outlinedButtonColors(contentColor = c.onSurface) } val content: @Composable RowScope.() -> Unit = { if (icon != null) { Icon(icon, contentDescription = null, Modifier.size(OvScale.SizeIcon)); Spacer(Modifier.width(OvScale.SpaceSm)) } Text(label, fontWeight = FontWeight.Bold) } val m = Modifier.heightIn(min = OvScale.SizeTap) if (kind == OvKind.Quiet) OutlinedButton(onClick, m, shape = RoundedCornerShape(OvScale.RadiusPill), colors = colors, border = BorderStroke(1.dp, c.outline), content = content) else Button(onClick, m, shape = RoundedCornerShape(OvScale.RadiusPill), colors = colors, content = content) }

iOS · SwiftUI

struct OvButton: View { let label: String var kind: OvKind = .primary var icon: String? = nil let action: () -> Void var body: some View { Button(action: action) { Label { Text(label).fontWeight(.bold) } icon: { if let icon { Image(systemName: icon) } } .frame(minHeight: OvScale.sizeTap) .padding(.horizontal, OvScale.spaceLg) } .buttonStyle(.borderedProminent) .buttonBorderShape(.capsule) .tint(kind == .danger ? OvTokens.colorStatusBadBase : kind == .quiet ? Color.clear : OvTokens.colorAccentStrong) .foregroundStyle(kind == .quiet ? OvTokens.colorTextPrimary : OvTokens.colorAccentOnStrong) } }

Markup

Default

<a class="ovk-btn ovk-btn--primary" href="/go"><svg class="ovk-i" viewBox="0 0 24 24" aria-hidden="true" focusable="false"><circle cx="12" cy="12" r="2.15"/><path d="M8.4 8.4a5.15 5.15 0 0 0 0 7.55M15.6 8.4a5.15 5.15 0 0 1 0 7.55M6 6a8.55 8.55 0 0 0 0 12.6M18 6a8.55 8.55 0 0 1 0 12.6"/></svg><span>Go live</span></a><button class="ovk-btn ovk-btn--quiet" type="button"><span>Not now</span></button><button class="ovk-btn ovk-btn--danger ovk-btn--small" type="button"><span>Delete</span></button>