Effects & triggers

Effects#

An effect makes the symbol move: it bounces, pulses, lights up layer by layer, scales, appears, disappears or swaps. Use one sparingly, to say that something changed or is still going on. An effect is an object in the symbol's effect property:

JSON
{"kind": "pulse", "trigger": "repeating", "speed": 1.2}
PropertyTypeDefaultDescription
kindstringnoneOne of bounce, pulse, variableColor, scale, appear, disappear, replace. Required.
triggerstringonAppearWhen the effect plays. One of onAppear, onChange, onHover, repeating.
speednumber1How fast it plays, from 0.25 to 4. A value outside the range is clamped, and the validator warns.
cumulativebooleanfalsevariableColor only: layers stay lit instead of lighting one at a time.
reversingbooleanfalsevariableColor only: the effect plays back and forth.

Triggers#

The trigger says what makes the effect play.

TriggerWhen it plays
onAppearOnce, about 0.35 seconds after the banner appears.
onChangeEach time something the symbol is bound to changes: its name after tokens are filled in, or a token in colors or variableValue.
onHoverEach time the pointer enters the symbol.
repeatingContinuously, for the effects that can run continuously: pulse, variableColor and scale.

For onChange, bind something: a variableValue of {signal} or a name that is a token such as {statusSymbol}. With nothing bound, nothing ever changes.

Kinds#

Each kind reacts to the triggers in its own way.

KindWhat it doesTriggers that work
bounceThe symbol hops once.onAppear, onChange, onHover.
pulseThe layers fade in and out.All four. With repeating it pulses for as long as the banner is up.
variableColorThe layers light up in sequence.All four. A single run lasts about 1.6 seconds divided by speed. repeating is continuous.
scaleThe symbol grows while the effect is active.All four. Timing is the same as variableColor.
appearThe symbol is hidden, then appears.It plays once after the banner appears, whatever the trigger.
disappearThe symbol fades away.onAppear: after it appeared. onChange and onHover: when that happens.
replaceThe symbol swaps with a transition when its name changes.onChange, with a name that contains a {token}.

Choosing an effect:

  • Use pulse, variableColor or scale for a continuous effect.
  • bounce is a single hop, and repeating does not play it.
  • A replace with a name that has no token never changes, and the validator warns.

Examples by effect#

bounce hops when the count changes. The badge shows the bound value:

JSON
{"type": "badge", "binding": "{count}", "color": "#FF3B30",
 "symbol": {"name": "envelope.fill", "scale": "small",
            "effect": {"kind": "bounce", "trigger": "onChange"}}}

pulse runs continuously on the issuer icon, to show that something is live:

JSON
{"type": "issuerIcon", "size": 28,
 "symbol": {"name": "dot.radiowaves.left.and.right", "renderingMode": "hierarchical",
            "colors": ["accent"],
            "effect": {"kind": "pulse", "trigger": "repeating", "speed": 0.8}}}

variableColor runs cumulative and reversing, driven by a field from the issuer:

JSON
{"type": "iconButton", "size": 22,
 "symbol": {"name": "wifi", "renderingMode": "hierarchical", "variableValue": "{signal}",
            "effect": {"kind": "variableColor", "trigger": "repeating",
                       "cumulative": true, "reversing": true}},
 "action": {"id": "dismiss", "label": "Dismiss", "kind": "dismiss"}}

scale grows when the pointer enters:

JSON
{"type": "iconButton", "size": 22,
 "symbol": {"name": "checkmark.circle.fill", "weight": "semibold",
            "effect": {"kind": "scale", "trigger": "onHover"}},
 "actionRef": "markRead"}

appear shows the symbol once the banner is up:

JSON
{"type": "issuerIcon", "size": 24,
 "symbol": {"name": "checkmark.seal.fill", "effect": {"kind": "appear"}}}

disappear fades a glyph away when the pointer enters:

JSON
{"type": "iconButton", "size": 20,
 "symbol": {"name": "xmark", "effect": {"kind": "disappear", "trigger": "onHover"}},
 "action": {"id": "dismiss", "label": "Dismiss", "kind": "dismiss"}}

replace swaps the glyph when the issuer's status changes the symbol name. The issuer sends a field statusSymbol with a value such as checkmark.circle or exclamationmark.triangle:

JSON
{"type": "iconButton", "size": 22,
 "symbol": {"name": "{statusSymbol}", "effect": {"kind": "replace", "trigger": "onChange"}},
 "action": {"id": "dismiss", "label": "Dismiss", "kind": "dismiss"}}

Common mistakes#

MistakeWhat happensFix
A misspelt name.The default look is drawn, and the validator warns.Copy the name from the SF Symbols app, or search with herald symbols.
palette with no colours.The tint and the tint at 55 percent are used, and the validator warns.Give it two or three colours.
multicolor with colors.colors is ignored, and the validator warns.Remove colors, or use palette.
cumulative or reversing on bounce.They are ignored, and the validator warns.They apply only to variableColor.
trigger: "repeating" on bounce or disappear.The effect never plays.Use onAppear, onChange or onHover, or choose pulse for something continuous.
replace with a name that has no token.Nothing changes, and the validator warns.Use a {token} in name and trigger: "onChange".
Expecting an effect in render_preview.Previews are static, so there is no motion.Check in the Designer's live preview, or send a test banner.
variableValue on a symbol without variable layers.It is ignored.Choose a symbol that supports it, such as wifi or speaker.wave.3.
Expecting effects on macOS 13, or with Reduce Motion.They are ignored by design.None. The banner is still readable.
placement: "only" where nothing else says what the button does.The label is dropped and only the tooltip keeps it.Keep the label, or use a clear icon.
placement: "only" on a badge.The pill is drawn with neither the symbol nor the value.Use leading or trailing on a badge.

Edit this page on GitHub

Esc
Getting started
Guides