Icons

Icons 20px

  • arrow-down
  • arrow-left
  • arrow-right
  • arrow-up
  • audio
  • audio-mute
  • burger
  • calendar
  • cart
  • check
  • circle-info
  • close
  • facebook
  • instagram
  • like
  • linkedin
  • loader
  • long-arrow-down
  • long-arrow-left
  • long-arrow-right
  • long-arrow-up
  • minus
  • minus-small
  • pause
  • pinterest
  • placeholder
  • play
  • plus
  • plus-small
  • profile
  • resize-handle
  • search
  • tiktok
  • twitter
  • warning

Icons 16px

  • arrow-down
  • arrow-left
  • arrow-right
  • arrow-up
  • circle-info
  • close
  • gift
  • loader
  • placeholder
  • promo-code
  • warning

Responsive — 16 below 768, 20 above

  • arrow-down
  • arrow-left
  • arrow-right
  • arrow-up
  • circle-info
  • close
  • loader
  • placeholder
  • warning

Payment icons

  • afterpay
  • american-express
  • apple-pay
  • boleto
  • diners-club
  • discover
  • elo
  • google-pay
  • hipercard
  • klarna
  • mastercard-dark
  • mastercard-light
  • paypal
  • pix
  • shop-pay
  • visa-dark
  • visa-light

Store badges

  • app-store
  • google-play

Flags (16)

  • australia / AU
  • brazil / BR
  • canada / CA
  • european-union
  • france / FR
  • germany / DE
  • israel / IL
  • italy / IT
  • new-zealand / NZ
  • spain / ES
  • sweden / SE
  • switzerland / CH
  • ukraine / UA
  • united-arab-emirates / AE
  • united-kingdom / GB
  • united-states / US

Labels

Styles

  • New Primary
  • Bestseller White on a card surface
  • Bestseller White on page — invisible by design
  • Pre-order Outline
  • Unisex Secondary
  • Save 20% Accent
  • Gift Leading icon — gift
  • Summer20 Leading icon — promo code
  • Bundle deal Longest production copy

Selection controls

Checkbox & radio

  • Default
  • Checked
  • Disabled
  • Disabled, checked
  • No label
  • Default
  • Selected
  • Disabled
  • Disabled, selected
  • Unchecked
  • Checked
  • Leading icon
  • Subtitle
  • Disabled
  • Group — selected
  • Group — unselected
  • Subtitle
  • Disabled

Scrollbar

  • Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Light
  • Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Scroll this box to see the thumb. The 16px area is a reserved gutter, so the bar never sits on top of the content.

    Dark

Counter

Specimens

  • 1 Default — minus disabled at the minimum
  • 3 Between the bounds — both buttons live
  • 10 At the maximum — plus disabled
  • 5 Step 5 — clamped to the ceiling
  • 1 Cart line — minus removes at 1
  • 2 Named item — labels say which product
  • 999 Three digits — the widest the box holds

Bound action — press a specimen to see what it receives

Price

Sizes and sale

  • Precio habitual $59.00s — no sale
  • Precio de venta $59.00 Precio habitual $159.00s — on sale
  • Precio habitual $59.00m — no sale
  • Precio de venta $59.00 Precio habitual $159.00m — on sale
  • Precio habitual $159.00Compare-at below the price — no fake discount
  • Precio habitual $0.00Zero — a free item still shows a price
  • Precio de venta $1,299.00 Precio habitual $2,599.00Four figures — the longest pair on one line
  • Empty price — the snippet renders nothing

Buttons

Add or duplicate blocks in the customizer to line up any combination, grouped by variant — click a button (loading is real, ~800ms) or tab to it.

Button

button — this.q('action-button').setAction(fn)
button — this.q('action-button').confirmAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)
Continue Continue Continue button — this.q('action-button').setAction(fn)
button — this.q('action-button').setAction(fn)

Button-icon

button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()
button-icon — same <action-button>, same setAction()

Button-icon-square

button-icon-square — same base as button-icon, .btn-icon--square modifier
button-icon-square — same base as button-icon, .btn-icon--square modifier
button-icon-square — same base as button-icon, .btn-icon--square modifier
button-icon-square — same base as button-icon, .btn-icon--square modifier
button-icon-square — same base as button-icon, .btn-icon--square modifier
button-icon-square — same base as button-icon, .btn-icon--square modifier

Button-play

button-play — white-inverse/m only, per Figma
button-play — white-inverse/m only, per Figma
button-play — white-inverse/m only, per Figma
button-play — white-inverse/m only, per Figma

Focus

Focus must always be visible. Secondary and white also carry a second, outer ring (control-border-focus-inverse) for contrast when they sit on top of media.

Light surfaces — primary: single ring. secondary: double ring (used over media)
Dark surfaces — single ring, inverse colour

Slide cart

Add or duplicate blocks in the customizer to line up any combination. Every specimen is live: click a chip's X (the loading cycle is real, ~800ms) or tab to it, and click a close control to flash the action bound to it. Only the X is clickable on a chip, and it is the chip's only tab stop, though hover and the focus ring cover the whole chip. Each is wired in one line, on every .design-guide__chip-action and every .design-guide__header-action: setAction(fn) on a chip, run(fn) on a close control. The footer's checkout CTA is wired the same way, on every .design-guide__footer-action: setAction(fn) again, because the CTA is a button and the footer holds no JS of its own.

Drawer header

Every specimen here is capped at 420px, the width of the slide-cart panel a drawer header actually renders in. Full-bleed across this page is a width the component never has, and at it even the long title fits on one line, so nothing clips. Resize the browser to compare 390 with 768 and up; the bar stays 63 and 65.

Your cart

Title only

Your cart

3 items

With count

Your cart with a deliberately very long heading that will not fit

3 items

Long title: clipped to an ellipsis

Your cart

3 items

Mobile preview: bare 20px close

Your cart

3 items

Desktop preview: 32px square close

Your cart

Close hover / pressed

Your cart

Close focus ring

Your cart

Close disabled

Chip

SUMMER20 Secondary
SUMMER20 Outline
SUMMER20 Promo chip
SUMMER20 No trailing icon: static, no control
SUMMER20 LoadingStatic specimen, click demo not wired.
SUMMER20 Disabled
SUMMER20 Hover / pressed
SUMMER20 Focus ring
SUMMER20 Leading icon: gift
SUMMER20 Leading icon: placeholder
SUMMER20 Trailing icon: arrow right
SUMMER20 Trailing icon: arrow down
SUMMER20 Trailing icon: circle info
SUMMER20 Trailing icon: warning

Slide cart footer

Pinned to the real slide-cart panel width the footer renders in: 390px below 768, where the drawer is full-bleed, and 420px from 768 up, the panel's own max-width. Each cell adds its own padding and border around that panel, so at 390 the specimens are wider than this page. They stay in one column, and the whole stack scrolls sideways (drag or swipe it) rather than the panel being squeezed. The total is a finished string the caller passes in: the footer reads nothing from cart and applies no money filter. The progress-tab slot is filled here with a dashed stub, because cart-progress-tab is its own component on its own ticket and is not on develop yet; with the slot empty the footer renders no box at all.

Default
No total: label only
Long CTA label
Long content: 11 marks wrap to a second row
Unknown mark keys are skipped
No payment marks
Progress tab slot
Mobile preview: 16 padding, 32 marks
Desktop preview: 24 padding, 32 marks
Desktop LG preview: 24 padding, 38 marks
CTA hover / pressed
CTA focus ring
CTA loadingStatic specimen, click demo not wired.
CTA disabled

Select

Select

  • Default, light
  • Default, dark
  • Filled, light
  • Filled, dark
  • Disabled, light
  • Disabled, dark
  • This is a hint text to help user

    Hint, light
  • This is a hint text to help user

    Hint, dark
  • This is an error message

    Error, light
  • This is an error message

    Error, dark
  • This is an error message

    Error, filled, light
  • This is an error message

    Error, filled, dark
  • Search
  • Icon, name, required
  • Flag
  • Search, custom copy, capped list

Select modal

    • United States
    • Canada
    • Ukraine
    • United Kingdom
    • Germany
    • France
    Light, default
    • United States
    • Canada
    • Ukraine
    • United Kingdom
    • Germany
    • France
    Light, search
    • United States
    • Canada
    • Ukraine
    • United Kingdom
    • Germany
    • France
    Dark, default
    • United States
    • Canada
    • Ukraine
    • United Kingdom
    • Germany
    • France
    Dark, search

Select tab

    • Label
    Light, default
    • Label
    Light, selected
    • Label
    Dark, default
    • Label
    Dark, selected
    • Label
    Disabled
    • Label
    With icon
    • Label
    With icon, selected
    • Label
    With flag
    • Label
    With flag, selected
    • A very long option label that has to truncate
    Content overflow

Date field

  • Default
  • Filled
  • Disabled
  • This is a hint text to help user

    Hint
  • This is an error message

    Error
  • This is an error message

    Error, filled

Date picker

  • SuMoTuWeThFrSa
    Default
  • MoTuWeThFrSaSu
    Week starts Monday

Input

Single-line text field, every state on both surfaces. Each sample string below is a snippet parameter — nothing is hardcoded in the component.

Interactive states

hover / pressed
Hover any field above, or press and hold.
focus
Click into a field, or Tab to it.
focus-typing
Focus a field and type. The placeholder sits next to the caret until you do.

Surface light

default

filled

disabled

error

Please fix the highlighted field

error-filled

Please fix the highlighted field

success

Success message!

hint

This is a hint text to help user

icon-left

icon-right

icon-both

long-value

button

button-filled

button-disabled

button-error

Please fix the highlighted field

button-success

Success message!

button-clear

button-async

Surface dark

default

filled

disabled

error

Please fix the highlighted field

error-filled

Please fix the highlighted field

success

Success message!

hint

This is a hint text to help user

icon-left

icon-right

icon-both

long-value

button

button-filled

button-disabled

button-error

Please fix the highlighted field

button-success

Success message!

button-clear

button-async

Textarea

Multi-line text field, every state on both surfaces. Each sample string below is a snippet parameter — nothing is hardcoded in the component.

Interactive states

hover / pressed
Hover any field above, or press and hold.
focus
Click into a field, or Tab to it.
focus-typing
Focus a field and type. The placeholder sits next to the caret until you do.
resize
Drag the grip in the bottom-right corner. Pointer only — it takes no keyboard. Height is clamped between the section's height and max height settings.

Surface light

default

filled

overflow

disabled

error

Please fix the highlighted field

error-filled

Please fix the highlighted field

success

Success message!

hint

This is a hint text to help user

Surface dark

default

filled

overflow

disabled

error

Please fix the highlighted field

error-filled

Please fix the highlighted field

success

Success message!

hint

This is a hint text to help user

Tooltip

Trigger and bubble are one component. The guide binds the log below through onToggle().

Interactive states

hover
Point at a trigger in the interactive row. The icon takes the hover colour and the panel opens after the open delay; moving away closes it after the close delay.
active
Press and hold a trigger.
focus-visible
Tab to a trigger: the focus ring shows and the panel opens. A mouse click opens it without the ring.
Escape
Closes the open panel and leaves focus on its trigger.
dismiss
Click the close button of an open panel. Focus returns to the trigger that opened it.
mutual exclusion
Open one float specimen, then another: the first closes itself.
disabled
The disabled specimen stays reachable with Tab and announces itself as disabled, but never opens.

Static review

  • Top · arrow start - the default
  • Top · arrow center
  • Top · arrow end
  • Bottom · arrow start
  • Right · arrow center
  • Left · arrow center
  • Title only
  • Description only - close button asked for and ignored
  • Close button off
  • Close button label - announces "Hide delivery details", not the shared Close translation
  • Disabled trigger - focusable, never opens
  • Long copy - wraps and scrolls
  • Narrow - max width 128px
  • Visible trigger label
  • Accessible name composed - the visible "Delivery" leads: "Delivery estimate details"
  • Accessible name verbatim - it already starts with "Delivery": "Delivery estimate details"
  • Accessible name verbatim - punctuation separator, not a space: "Delivery: estimate details"
  • 20px trigger icon
  • Warning icon
  • Placeholder icon

Interactive

  • Hover - the default event
  • Click to open
  • Flip off - keeps the authored side
  • Pair 1 of 2 - opening this closes the other
  • Pair 2 of 2 - opening this closes the other

Viewport edges

  • Left edge. Stays on the right: the panel lands 8px from the viewport and the arrow tracks the trigger centre.
  • Right edge. Flips to the left: the panel right edge lands 8px from the viewport.
  • Top edge. Scroll the trigger up to the top band, then open it: the panel flips below, the arrow offset clamps to 24px, apex within ~2px of the icon centre.
Bound through onToggle() - open a specimen to see what it reports

Here's what you get as a BetterMe creator:

Here's what you get as a BetterMe creator:

  • Commission that grows with you

    Start at 10% and earn more with every sale. No cap. Top performers also get weekly Ad Boost on their best videos.

  • First access to new drops

    Get fresh collections before they go live, so your content is always ahead of the trend.

  • Ready-to-use briefs, hooks and format

    We analyze what's already converting and share it with you. Skip the guesswork and start posting.

  • Free product to start

    Pick 1 bestseller (Full-Length Catsuit or Sleek Shorts Catsuit) and claim one of 5 free samples before they're gone.