This is a visual guide to the features that Dynamic Flow supports. Look in the top right of the code samples for links to copy and launch them in our interactive sandbox, where you can edit them further.
These components are used for the display of non-interactive content. In dynamic flow, we call these "layout" components.
Shows an attention-grabbing message. Bold and italic markdown are supported, but no links.
alert {
markdown = "Exchange rates are unstable right now, so we can't guarantee this rate."
context = Context.WARNING
}Display is a control on the heading component. It can be used for headlines, typically on a success screen.
heading {
text = "Whoa, that was fast!"
control = "display"
}Divider is a visual asset used to create a separation between content on the screen
divider { }The heading component can be used to provide a title for a step or section. Different sizes can be used to provide a hierarchy within a step.
heading {
text = "Money for here, there and everywhere"
}The image component allows an illustration to be displayed via URN.
media {
media = Media.Image.build {
uri = "urn:wise:illustrations:globe"
accessibilityDescription = "An image"
}
}Displays an image in the layout. Supports http(s) and data (base64).
media {
media = Media.Image.build {
uri = "/staticrab/dynamic-flow-docs/example.jpg"
accessibilityDescription = "An image"
}
}Gives users positive and negative instructions, or explains what a feature does and doesn't do.
instructions {
items {
item {
text = "Make an initial money transfer"
context = Context.POSITIVE
}
item {
text = "Pay extra hidden fees for transfers"
context = Context.NEGATIVE
}
}
}A list of elements that don't require interaction.
list {
title = "Transactions"
items {
item {
title = "Starbucks"
description = "Coffee"
supportingValues {
value = "+100 GBP"
subvalue = "Refund"
}
media = Media.Avatar.build {
content { uri { uri = "urn:wise:icons:takeaway" } }
}
}
item {
title = "BBC"
description = "TV License"
supportingValues {
value = "-5 GBP"
subvalue = "Payment Success"
}
media = Media.Avatar.build {
content {
uri {
uri = "urn:wise:icons:person"
badgeUri = "urn:wise:icons:bills"
}
}
accessibilityDescription = "An image of the BBC"
}
}
item {
title = "Pineapple Pizza Express"
description = "Pizza"
supportingValues {
value = "-13 GBP"
subvalue = "Transaction pending"
}
media = Media.Avatar.build {
content { text { text = "PE" } }
}
}
}
}The loading indicator gives the user an indication that something is happening.
loadingIndicator { }Markdown is a block of rich content defined using markdown. If you just need plain text, consider using a paragraph.
markdown {
content = "**Sending money shouldn't cost the earth**. Wise can save you [up to 9x](https://wise.com/help/articles/2974130/how-does-wise-compare-to-leading-banks) compared to UK high street banks."
}Paragraph is a block of plain text content. If you need richer formatting and layout options, consider using the markdown component.
paragraph {
text = "The Wise account is the universal way for you to manage money internationally. It's made for the world. And it's built to save your money and time, so you can do more of the things you love."
}Progress shows the progress of something, visually and with an accompanying description.
progress {
title = "Send 5,550 GBP"
description = "You have 3 days to reach your goal."
progress = 0.55F
progressText = "200 GBP to go"
}A list of read-only labels and values, useful when displaying information for the user to review.
review {
title = "Please review your transfer"
fields {
field {
label = "Recipient"
value = "Florence Jones"
}
field {
label = "Amount"
value = "$6550"
}
field {
label = "To be sent"
value = "July 21, 2024"
}
}
callToAction {
title = "Edit"
behavior = ActionBehavior.build {
action {
url = "/edit"
}
}
}
}A list of items with optional states, subtitles, and icons.
statusList {
items {
item {
title = "Set up your card"
description = "Get set up in seconds with a digital card."
icon = Icon.Named("chip")
status = StatusListLayout.Status.DONE
}
item {
title = "Open an account"
description = "Open a balance in one of 50+ currencies"
icon = Icon.Named("globe")
}
}
}Form components give users way to input data. They're used inside forms.
Checkboxes let users select zero, one, or multiple items from a list.
obj {
id = "#schema"
properties {
boolean("terms") {
title = "I agree to the terms and conditions"
}
}
}A date input lets users enter a date.
obj {
id = "#schema"
properties {
string("date") {
title = "Date of Birth"
format = StringSchema.Format.DATE
}
}
}The date picker lets users pick a date from a calendar.
obj {
id = "#schema"
properties {
string("date") {
title = "Transfer date"
format = StringSchema.Format.DATE
control = Control.Schema.String.DATE_LOOKUP
placeholder = "Select a date"
minimum = "2023-01-01"
maximum = "2026-12-31"
}
}
}Tabs let the user choose between different groups of inputs to fill out. These are distinct from Layout tabs, which are only used to control the layout of the page, and do not alter the data which will be sent on submit.
obj {
id = "#schema"
properties {
oneOf("details") {
title = ""
control = Control.Schema.OneOf.TAB
schemas {
obj {
title = "Local"
properties {
string("account-number") {
title = "Account number"
}
string("sort-code") {
title = "Sort code"
}
}
}
obj {
title = "International"
properties {
string("iban") {
title = "IBAN"
}
string("bic") {
title = "BIC"
}
}
}
}
}
}
}Integer fields restrict input to whole numbers only (no decimals).
obj {
id = "#schema"
properties {
integer("age") {
title = "Age"
}
}
}Number fields restrict input to numbers only (including decimals).
obj {
id = "#schema"
properties {
number("amount") {
title = "Amount"
}
}
}Money Input allows for textual input of an amount and selection of a currency.
money {
id = "#schema"
title = "Sending"
currencies {
const {
value("EUR")
title = "EUR"
description = "Euro"
}
const {
value("GBP")
title = "GBP"
description = "British pound"
}
const {
value("USD")
title = "USD"
description = "US dollar"
}
}
}Number fields restrict input to numbers only (including decimals).
obj {
id = "#schema"
properties {
number("amount") {
title = "Amount"
}
}
}A password field lets users enter a password securely, by obscuring the text.
obj {
id = "#schema"
properties {
string("password") {
title = "Password"
control = Control.Schema.String.PASSWORD
autocompleteHint(AutocompleteToken.PASSWORD)
}
}
}A phone number input gives users a convenient way to enter their phone number.
obj {
id = "#schema"
properties {
string("phone") {
title = "Phone number"
control = Control.Schema.String.PHONE_NUMBER
autocompleteHint(AutocompleteToken.PHONE_NUMBER)
}
}
}A radio lets users select a single item from a mutually exclusive list.
obj {
id = "#schema"
properties {
oneOf("account") {
title = "Which account type would you like to open?"
control = Control.Schema.OneOf.RADIO
schemas {
const {
title = "Business"
value("BUSINESS")
}
const {
title = "Personal"
value("PERSONAL")
}
}
}
}
}To capture a list of data, you can use a form that can be filled in multiple times. Items can be edited or deleted.
val repeatableStepExample = Step.build {
id = "Repeatable"
title = ""
schemas {
obj {
id = "#schema"
properties {
list("residency") {
title = "Tax residency"
addItemTitle = "Add a tax residency"
editItemTitle = "Edit a tax residency"
items = OneOfSchema.build {
schemas {
obj {
title = "United Kingdom"
summary = Summary.Provider(providesMedia = true)
media = Media.Avatar.build {
content { uri { uri = "urn:wise:countries:gb:image" } }
}
properties {
const("country") {
title = "United Kingdom"
value("UK")
summary = Summary.Provider(providesTitle = true)
}
}
}
obj {
title = "Spain"
summary = Summary.Provider(providesMedia = true)
media = Media.Avatar.build {
content { uri { uri = "urn:wise:countries:es:image" } }
}
properties {
const("country") {
title = "Spain"
value("ES")
summary = Summary.Provider(providesTitle = true)
}
string("taxNumber") {
title = "NIE Number"
summary = Summary.Provider(providesDescription = true)
}
}
}
}
}
}
}
}
}
layout {
form {
schemaId = "#schema"
}
}
model = encodeToJsonElement(
mapOf(
"residency" to listOf(
mapOf("country" to "UK"),
mapOf(
"country" to "ES",
"taxNumber" to "12345678"
)
)
)
)
}A different treatment for tabular content.
obj {
id = "#schema"
properties {
oneOf("paymentMethod") {
title = ""
control = Control.Schema.OneOf.SEGMENTED
schemas {
const {
title = "ACH"
value("ACH")
}
const {
title = "Wire"
value("WIRE")
}
const {
title = "SWIFT"
value("SWIFT")
}
}
}
}
}A select lets a user pick an option from a list of options (typically used for longer lists).
obj {
id = "#schema"
properties {
oneOf("account") {
title = "Choose a balance currency"
schemas {
const {
title = "EUR"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:eur:image" } }
}
description = "Euro"
value("EUR")
alert {
markdown = "This is the default currency for your account."
context = Context.NEUTRAL
}
}
const {
title = "GBP"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:gbp:image" } }
}
description = "British pound"
value("GBP")
}
const {
title = "USD"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:usd:image" } }
}
description = "United States dollar"
value("USD")
}
}
}
}
}A multi-select lets a user pick multiple options from a list.
obj {
id = "#schema"
properties {
list("currencies") {
title = "Select your preferred currencies"
addItemTitle = ""
editItemTitle = ""
items = OneOfSchema.build {
schemas {
const {
title = "USD"
description = "United States dollar"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:usd:image" } }
}
value("USD")
}
const {
title = "GBP"
description = "British pound"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:gbp:image" } }
}
value("GBP")
}
const {
title = "EUR"
description = "Euro"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:eur:image" } }
}
value("EUR")
}
}
}
}
}
}An inline multi-select lets a user pick multiple options from a list that is displayed inline.
obj {
id = "#schema"
properties {
list("currencies") {
title = "Select your preferred currencies"
addItemTitle = ""
editItemTitle = ""
control = Control.Schema.Array.INLINE
items = OneOfSchema.build {
schemas {
const {
title = "USD"
description = "United States dollar"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:usd:image" } }
}
value("USD")
}
const {
title = "GBP"
description = "British pound"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:gbp:image" } }
}
value("GBP")
}
const {
title = "EUR"
description = "Euro"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:eur:image" } }
}
value("EUR")
}
}
}
}
}
}An inline checkbox group lets a user pick multiple options from a list with checkboxes.
obj {
id = "#schema"
properties {
list("currencies") {
title = "Select your preferred currencies"
addItemTitle = ""
editItemTitle = ""
control = Control.Schema.Array.INLINE_CHECKBOX_GROUP
items = OneOfSchema.build {
schemas {
const {
title = "USD"
description = "United States dollar"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:usd:image" } }
}
value("USD")
}
const {
title = "GBP"
description = "British pound"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:gbp:image" } }
}
value("GBP")
}
const {
title = "EUR"
description = "Euro"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:currencies:eur:image" } }
}
value("EUR")
}
}
}
}
}
}A switch component provides a toggle interface for boolean values, offering an alternative to checkboxes.'
boolean("recurringPayment") {
title = "Recurring payment"
control = "switch-item"
defaultValue = true
}A text field lets users enter a single line of text.
obj {
id = "#schema"
properties {
string("name") {
title = "Full name"
}
}
}A text area is a field that lets users enter several lines of text.
obj {
id = "#schema"
properties {
string("feedback") {
title = "Please leave your comments below"
control = Control.Schema.String.TEXTAREA
}
}
}An upload field allows the user to upload one or more files that fit certain criteria. This example uses persist async, where data is stored to a separate endpoint in exchange for a token. We also support synchronous uploads, but using persist-async is preferred.
obj {
id = "#schema"
properties {
string("file") {
persistAsync {
url = "/upload"
method = HttpMethod.POST
param = "bodyAttribute"
idProperty = "token"
schema = BlobSchema.build {
source = Upload.Source.FILE
title = "Invoice"
description = "PNG, JPG, or PDF, less than 5mb"
accepts = listOf(
"image/png",
"image/jpg",
"application/pdf"
)
}
}
}
}
}Similar to the upload component, except it allows the upload of multiple files. This example uses persist async, where data is stored to a separate endpoint in exchange for a token. We also support synchronous uploads, but using persist-async is preferred.
obj {
id = "#schema"
properties {
list("files") {
title = ""
addItemTitle = ""
editItemTitle = ""
items = StringSchema.build {
persistAsync {
url = "/persist"
method = HttpMethod.POST
param = "file"
idProperty = "token"
schema = StringSchema.build {
source = Upload.Source.FILE
format = StringSchema.Format.BASE64URL
title = "Source of wealth documents"
}
}
}
}
}
}These components give the user a way to interact and take actions.
A button lets the user perform an action (such as submitting the form) with a tap or a click.
button {
title = "Continue"
control = "primary"
behavior = ActionBehavior.build {
action {
url = "/submit"
method = HttpMethod.POST
}
}
}Decisions give users a rich way to choose between options and navigate to the next step.
decision {
title = "Decision title"
options {
option {
title = "Top up"
description = "Get started by adding money to your balance"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:icons:plus" } }
}
behavior = ActionBehavior.build {
action {}
}
}
option {
title = "Connect your bank account"
description = "Move money with ease by connecting another account"
media = Media.Avatar.build {
content { uri { uri = "urn:wise:icons:bank" } }
}
behavior = ActionBehavior.build {
action {}
}
}
}
}Filtering can be enabled on Deicsion components to allow easier selection from a long list.
decision {
title = "Recent Purchases"
control = "filtered"
options {
option {
title = "Invoice for Consulting"
description = "Down Under LTD"
supportingValues {
value = "100 AUD"
}
media = Media.Avatar.build {
content { uri { uri = "urn:wise:countries:au:image" } }
}
behavior = ActionBehavior.build {
action {
url = "/au-currency"
}
}
}
option {
title = "TV License"
description = "British Broadcasting Network"
supportingValues {
value = "50 GBP"
}
media = Media.Avatar.build {
content { uri { uri = "urn:wise:countries:gb:image" } }
}
behavior = ActionBehavior.build {
action {
url = "/gbp-currency"
}
}
}
option {
title = "Enchantment Table"
description = "Mooshroom Industries"
supportingValues {
value = "30 USD"
}
media = Media.Avatar.build {
content { uri { uri = "urn:wise:countries:us:image" } }
}
behavior = ActionBehavior.build {
action {
url = "/us-currency"
}
}
}
option {
title = "Mjölnir"
description = "B&S Manufacturing"
supportingValues {
value = "10 NOR"
}
media = Media.Avatar.build {
content { uri { uri = "urn:wise:countries:no:image" } }
}
behavior = ActionBehavior.build {
action {
url = "/no-currency"
}
}
}
}
}Component that allows the user to lookup data remotely and select a result based on the search query.
search {
method = HttpMethod.GET
url = "/companies"
param = "search"
title = "Company"
emptyMessage = "No company found"
}Layout components give you control over the layout of your screen.
Aligns the contents of a layout relative to its parent.
heading {
align = Align.CENTER
text = "Money for here, there and everywhere"
}A box wraps other components inside a box.
box {
width = Size.MD
control = Control.Layout.Box.BORDERED
components {
paragraph {
text = "Sending money shouldn't cost the earth. That's why we charge you as little as possible when you transfer and exchange money internationally."
}
}
}Columns give you a way to split content into two vertical sections.
columns {
left {
heading {
text = "Money for here, there and everywhere"
}
}
right {
paragraph {
text = "Sending money shouldn't cost the earth. That's why we charge you as little as possible when you transfer and exchange money internationally – you can save up to 9x compared to UK high street banks."
}
}
}Defines the spacing above each component.
heading {
text = "Money for here, there and everywhere"
}
paragraph {
margin = Size.LG
text = "The Wise account is the universal way for you to manage money internationally."
}Modals allow you to show dialogs or bottom sheets over your main step.
button {
title = "Terms and conditions"
behavior = ModalBehavior.build {
title = "Terms and conditions"
content {
paragraph {
text = "Welcome to our application. If you continue to browse and use this application, you are agreeing to comply with and be bound by the following terms and conditions of use, which together with our privacy policy govern our relationship with you in relation to this application."
}
}
}
}A section header with an optional action
section {
title = "Primary Tenant"
components {
markdown {
content = "Simon Claw"
}
}
}
section {
title = "Co-applicant"
components {
markdown {
content = "Tim Cheese"
}
}
callToAction {
title = "Edit"
accessibilityDescription = "This is an edit button to edit co-applicant details"
behavior = ActionBehavior.build {
action {
url = "/edit"
method = HttpMethod.POST
}
}
}
}Tabs can be used to display content in a tabular form. These are for page layout only - if you want to use form inputs in tabs we recommend using Form tabs.
tabs {
tabs {
tab {
title = "Unpaid"
components {
decision {
options {
option {
media = Media.Avatar.build {
content { uri { uri = "urn:wise:icons:clock" } }
}
title = "Joe Bloggs"
description = "15 GBP"
behavior = ActionBehavior.build {
action {
url = "/pay"
}
}
}
option {
media = Media.Avatar.build {
content { uri { uri = "urn:wise:icons:clock" } }
}
title = "Mary Smith"
description = "20 EUR"
behavior = ActionBehavior.build {
action {
url = "/pay"
}
}
}
}
}
}
}
tab {
title = "Paid"
components {
decision {
options {
option {
media = Media.Avatar.build {
content { uri { uri = "urn:wise:icons:check" } }
}
title = "Jane Doe"
description = "10 GBP"
behavior = ActionBehavior.build {
action {
url = "/view"
}
}
}
}
}
}
}
}
}Use these form features to make your form more usable and readable.
Autocomplete hints help browsers, operating systems and assistive technologies understand the type of a field.
string("email") {
title = "Email"
autocompleteHint = listOf(AutocompleteToken.EMAIL)
}Group input components into sections with headings.
obj {
id = "#schema"
title = "Personal details"
properties {
string("name") {
title = "Full name"
}
}
}Most schemas support help text, which can be used to provide extra information that may be helpful to users when filling out a field.
string("iban") {
title = "IBAN"
help {
markdown = "IBANs are long account numbers used by banks for cross-border transfers. Each country structures this number differently, but it always starts with a **2 digit country code** (e.g. DE for Germany)."
}
}Use a model to pre-fill your form with data.
val modelStepExample = Step.build {
id = "Model"
title = ""
schemas {
obj {
id = "#schema"
required = listOf("name")
properties {
string("name") {
title = "Name"
}
}
}
}
layout {
form {
schemaId = "#schema"
}
}
model = encodeToJsonElement(mapOf("name" to "Florence Jones"))
}Submit part of a form asynchronously and include a token in its place.
string {
id = "#schema"
persistAsync {
url = "/persist"
method = HttpMethod.POST
param = "number"
idProperty = "token"
schema = StringSchema.build {
title = "Card number"
}
}
}Set a placeholder on your form field.
string("name") {
title = "Name"
placeholder = "First and last names"
}Set a form field to be required.
obj {
id = "#schema"
required = listOf("name")
properties {
string("name") {
title = "Name"
}
}
}Media represents a visual asset which can be displayed in conjunction with other components. Media can either be an avatar or an image.
Avatars can use assets via URIs. These can be URLs, or known URNs (currently icons and flags are supported). Avatars can also include badges with a URI.
media = Media.Avatar.build {
content {
uri {
uri = "urn:wise:icons:person"
badgeUri = "urn:wise:icons:plus?=background-color=brand-bright-green"
}
}
}Avatars can also contain text, usually referencing a person or entity by their initials.
item {
title = "250 GBP to Amigo Burrito"
description = "Declined — not enough money in your account"
media = Media.Avatar.build {
content {
text {
text = "AB"
badgeUri = "urn:wise:icons:plus?=background-color=sentiment-warning"
}
}
}
inlineAlert {
content = "Insufficient funds"
context = Context.WARNING
}
}Media can also be an Image, which avoids wrapping the content in an avatar.
media = Media.Image.build {
uri = "/staticrab/dynamic-flow-docs/example.jpg"
}We have several ways of validating form input, supporting simple, immediate validation and more complex validation that can be performed on the server. See also the Global Error for a way to show a step level error.
Client side validation. Validation is triggered on blur or submission.
string("password") {
title = "Please enter a password"
description = "Must be at least 8 characters long"
minLength = 8
}Include errors in your step to be rendered as errors in your form. Supports form validation errors and global errors. Errors will be cleared on edit.
errors {
validation = buildJsonObject {
put("password", "Please use a password you haven't used before")
}
error = "Something went wrong. Please try again."
}Validation messages let you provide custom messages for validation errors.
string("password") {
title = "Please enter a password"
description = "Must be at least 8 characters long"
minLength = 8
maxLength = 25
validationMessages = mapOf(
"minLength" to "Your password is too short.",
"maxLength" to "Your password is too long."
)
}Use the pattern prop to enforce a pattern on a field. Validation is triggered on blur or submission.
string("accountNumber") {
title = "Account number"
description = "This is an 8 digit number starting with 0"
pattern = "0[0-9]{7}"
control = Control.Schema.String.NUMERIC
}Back navigation can be used to redirect the user when the default back behaviour doesn't make sense.
navigation {
back {
title = "Back"
action {
url = "/payment-method-selection"
}
}
}Open the camera to take a picture.
val cameraStepExample = Step.build {
id = "Camera"
title = ""
schemas {
string {
id = "#schema"
persistAsync {
url = "/persist"
method = HttpMethod.POST
param = "image"
idProperty = "token"
schema = BlobSchema.build {
source = Upload.Source.CAMERA
accepts = listOf("image/*")
}
}
}
}
layout {
form {
schemaId = "#schema"
}
}
}Open a URL in the browser, or in another app on mobile.
val externalStepExample = Step.build {
id = "External"
title = ""
external {
url = "https://google.com"
}
layout {}
}Show a general error, not related to any particular schema.
val globalErrorStepExample = Step.build {
id = "GlobalError"
title = ""
layout {}
errors {
error = "Something has gone wrong. Please try again soon."
}
}Poll an endpoint while waiting for a server state to change.
val pollingStepExample = Step.build {
id = "Polling"
title = "Polling Example"
polling {
url = "/polling/get-status?id=12345"
delay = 5
timeout = 60
maxAttempts = 100
onError {
behavior = ActionBehavior.build {
action {}
}
}
}
layout {}
}This mobile only feature offers more control over how new steps are added to the navigation stack. The default is to push on to the stack, but setting this can change the behaviour to replace, remove previous or even clear the stack.
navigation {
stackBehavior = Navigation.StackBehavior.REPLACE_CURRENT
}Toolbar is used to display a selection of buttons on the user's toolbar.
toolbar {
items = listOf(
Toolbar.Button.build {
title = "Earn £75"
control = "primary"
behavior = ModalBehavior.build {
title = "Invite your friends"
content {
paragraph {
text = "For every 3 friends you refer to Wise, you will earn £75"
}
button {
title = "Close"
behavior = DismissBehavior()
}
}
}
},
Toolbar.Button.build {
title = "Help"
control = "secondary-neutral"
media = Media.Avatar(
accessibilityDescription = "Help",
content = listOf(
Media.Avatar.UriContent(
uri = "urn:wise:icons:question-mark-circle",
badgeUri = null
)
)
)
behavior = LinkBehavior.build {
url = "https://wise.com/help/articles/2596978/how-do-i-add-money-to-my-account"
}
}Behaviors define what happens when a user interacts with an element. They can be attached to various components to customize their functionality.
Performs an action (like submitting a form) when the behavior is triggered.
button {
control = "primary"
title = "Confirm and send"
behavior = ActionBehavior.build {
action {
url = "/transfers/confirm"
method = HttpMethod.POST
}
}
}Refreshes the current step when the behavior is triggered, using the refreshUrl property of Step.
button {
control = "primary"
title = "Check Status"
behavior = RefreshBehavior()
}Opens a link when the behavior is triggered.
button {
control = "tertiary"
title = "Learn more about Direct Debits"
behavior = LinkBehavior.build {
url = "https://wise.com/help/articles/2977956/getting-started-with-direct-debits"
}
}Places the provided content into the system clipboard when triggered.
review {
fields {
field {
label = "Cardholder name"
value = "Emmett Brown"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "Emmett Brown"
}
}
}
field {
label = "Card number"
value = "0118 0135 2610 1985"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "0118 0135 2610 1985"
}
}
}
field {
label = "Expiry date"
value = "10/85"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "10/85"
}
}
}
field {
label = "Security code"
value = "088"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "088"
}
}
}
field {
label = "Billing address"
value = "1646 Riverside Drive, Hill Valley, CA 95420, United States"
}
}
}Opens a modal when the behavior is triggered.
button {
control = "primary"
title = "Card details"
behavior = ModalBehavior.build {
title = "Card details"
content {
review {
fields {
field {
label = "Cardholder name"
value = "Emmett Brown"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "Emmett Brown"
}
}
}
field {
label = "Card number"
value = "0118 0135 2610 1985"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "0118 0135 2610 1985"
}
}
}
field {
label = "Expiry date"
value = "10/85"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "10/85"
}
}
}
field {
label = "Security code"
value = "088"
callToAction {
title = "Copy"
behavior = CopyBehavior.build {
content = "088"
}
}
}
field {
label = "Billing address"
value = "1646 Riverside Drive, Hill Valley, CA 95420, United States"
}
}
}
}
}
}Dismisses the top-most modal content when the behavior is triggered.
button {
title = "Dismiss"
behavior = DismissBehavior()
}We often use a splash screen at the end of a flow to confirm the user's action.
You can specify a Step with a control of "splash". On mobile, this will center the layout vertically. On web, it will add some top margin to the entire layout.
Make sure your heading component specifies "control": "display" to use the correct font.
val splashStepExample = Step.build {
id = "splash"
title = ""
control = Control.Step.SPLASH
layout {
media {
media = Media.Image.build {
uri = "urn:wise:illustrations:megaphone"
}
}
heading {
text = "Success!"
control = Control.Layout.Heading.DISPLAY
align = Align.CENTER
}
paragraph {
text = "Congratulations! Everything went... according to plan."
align = Align.CENTER
margin = Size.XL
}
}
footer {
button {
title = "Continue"
control = Control.Layout.Button.PRIMARY
behavior = ActionBehavior.build {
action {
exit = true
}
}
}
}
}You can specify a Step with a control of "splash-celebration". On mobile, this will center the layout vertically and automatically change the theme to "forest-green". On web, the DynamicFlow component cannot set the theme for you. Instead, the onThemeChange callback prop will be triggered; and you can use this to set the theme in your app.
Make sure your heading component specifies "control": "display" to use the correct font.
val splashCelebrationStepExample = Step.build {
id = "splashcelebration"
title = ""
control = Control.Step.SPLASH_CELEBRATION
layout {
media {
media = Media.Image.build {
uri = "urn:wise:illustrations:plane?+type=animated"
}
}
heading {
text = "Success!"
control = Control.Layout.Heading.DISPLAY
align = Align.CENTER
}
paragraph {
text = "Congratulations! Everything went... according to plan."
align = Align.CENTER
margin = Size.XL
}
}
footer {
button {
title = "Continue"
control = Control.Layout.Button.PRIMARY
behavior = ActionBehavior.build {
action {
exit = true
}
}
}
}
}