sRFC 29 - Input types of blinks and actions
TLDR
Add new input types within blink clients to improve the user experience and unlock new use cases for Action builders.
Rationale
The current Solana Actions and blinks specification only supports a single, generic input type of a non-structured text box. While this basic input is useful, having more explicit and declarative input types would allow Action builders and blink clients to unlock new use cases and improve the user experience of using blinks across the internet.
Current Spec
Per the current specification, an Action api will declare what user input fields it desires using the structured response (ActionGetResponse
) from the initial GET request, specifically via any child item of links.actions
containing the parameters
field.
The current specification is this:
/**
* Response body payload returned from the Action GET Request
*/
export interface ActionGetResponse {
/** image url that represents the source of the action request */
icon: string;
/** describes the source of the action request */
title: string;
/** brief summary of the action to be performed */
description: string;
/** button text rendered to the user */
label: string;
/** UI state for the button being rendered to the user */
disabled?: boolean;
/** */
links?: {
/** list of related Actions a user could perform */
actions: LinkedAction[];
};
/** non-fatal error message to be displayed to the user */
error?: ActionError;
}
/**
* Related action on a single endpoint
*/
export interface LinkedAction {
/** URL endpoint for an action */
href: string;
/** button text rendered to the user */
label: string;
/** parameters used to accept user input within an action */
parameters?: ActionParameter[];
}
Any ActionParameter
declared will result in a plain text input be rendered to the user (with the optional placeholder text) in order to accept their input, which ultimately gets sent the Action api endpoint via the POST request.
Additionally, the user input data is only sent to the Action api via query parameters and template literals (e.g. {name}
) declared within the specific linked actionâs href
field. This presents limitations and complexities when accepting longer user input values or more complex input types.
/**
* Parameter to accept user input within an action
*/
export interface ActionParameter {
/** parameter name in url */
name: string;
/** placeholder text for the user input field */
label?: string;
/** declare if this field is required (defaults to `false`) */
required?: boolean;
}
Proposal
-
To support sending longer and more complex user input to the Action API (via the POST request), user input should be optionally sent via the POST request
body
, not just templatized query parameters (like the userâsaccount
address is already being sent).
All user input should be sent to the Action API as follows for eachLinkedAction
:- any input
parameters
specified via template literals in query parameters of thehref
value should have their respective user input values sent via the its named query parameter (this is how the spec currently works) - all remaining input
parameters
(aka those that do NOT have a template literal declared in thehref
) should be sent in thebody
of the POST request (along side the userâsaccount
, but should never be able to modify theaccount
value) - Note: if a template literal for any of the
parameters
is found, it should not be sent via thebody
. This will reduce the total data sent over the network and is always a best practice to not send duplicate data.
In the end, this allows developers to accept user input via query parameters (not breaking existing applications) or via the POST request
body
. And effectively set an implicit default of using the POST body to receive the user input, just like a typical HTML form. - any input
-
Update the
ActionParameter
to support declaring different types of user input. In many cases, thistype
will resemble the standard HTML input element.This new new
type
attribute should have a type declaration as follows:
/**
* Input type to present to the user
* @default `text`
*/
export type ActionParameterType =
| "text"
| "email"
| "url"
| "number"
| "date"
| "datetime-local"
| "checkbox"
| "radio"
| "textarea"
| "select";
Each of the proposed type
values should normally result in a user input field that resembles a standard HTML input
element of the corresponding type
(i.e. <input type="email" />
) to provide better client side validation and user experience:
text
- equivalent of HTML âtextâ input elementemail
- equivalent of HTML âemailâ input elementurl
- equivalent of HTML âurlâ input elementnumber
- equivalent of HTML ânumberâ input elementdate
- equivalent of HTML âdateâ input elementdatetime-local
- equivalent of HTML âdatetime-localâ input elementcheckbox
- equivalent to a grouping of standard HTML âcheckboxâ input elements. The Action api should returnoptions
as detailed below. The user should be able to select multiple of the provided checkbox options.radio
- equivalent to a grouping of standard HTML âradioâ input elements. The Action api should returnoptions
as detailed below. The user should be able to select only one of the provided radio options.- Other HTML input types not specified above (
hidden
,button
,submit
,file
, etc) are not supported at this time.
In addition to the elements resembling HTML input types above, the following user input elements are also supported:
textarea
- equivalent of HTML textarea element. Allowing the user provide multi-line input.select
- equivalent of HTML select element, allowing the user to experience a âdropdownâ style field. The Action api should returnoptions
as detailed below.
When type
is set as select
, checkbox
, or radio
then the Action api should include an array of options
that each provide a label
and value
at a minimum. Each option may also have a selected
value to inform the blink-client which of the options should be selected by default for the user (see checkbox
and radio
for differences).
interface ActionParameterSelectable extends ActionParameter {
options: Array<{
/** displayed UI label of this selectable option */
label: string;
/** value of this selectable option */
value: string;
/** whether or not this option should be selected by default */
selected?: boolean
}>;
}
If no type
is set or an unknown/unsupported value is set, blink clients should default to text
and render a simple text input (just as they do now).
The Action API is still responsible to validate and sanitize all data from the user input parameters, enforcing any ârequiredâ user input as necessary.
For platforms other that HTML/web based ones (like native mobile), the equivalent native user input component should be used to achieve the equivalent experience and client side validation as the HTML/web input types described above.
Note: As with the current spec, if a LinkedAction
does not declare the parameters
attribute, then no user input is requested by the Action api and blink clients should continue to render a single button that performs the POST request to the href
endpoint. This proposal does not change that.
Closing Notes
With the support of more input types, developers will be able to build more complex blinks and accept more user input. Having âtoo manyâ user input fields could result in a reduced user experience and also make users less likely to actually enter all the requested inputs.
To avoid UI bloat and degrading user experiences, blink-clients are likely to impose âsoft limitsâ on the number of input fields they display. While this Actions/blink specification avoids taking an opinionated approach on the UI layer of blinks, the following is a reasonable guideline (and used by Dialectâs blinks SDK today):
- 10 buttons + 3 inputs (if separate Actions)
- 10 inputs (if itâs a form, and other actions are not rendered if there is a form in the response)
As such, Action API developers should limit the number of input parameters
they request as blink-clients may limit how many input fields get shown to users. Developers should also keep in mind that if a user does not see all input fields (because the blink-client soft limits them as described above), then the user will have no way to enter a value. Therefore if all these fields are required by the Actions API, the user will NOT be able to actually execute your Action and get a transaction.