Introduction
StepFlow is a library that lets you build data-defined user flows.
User flows are multi-step (or multi-screen) user experiences that drive a user towards an outcome. Common examples are user registrations and store cart checkouts.
StepFlow manages user flows with a data-orientation. At its core, it tracks data dependencies between steps to ensure they work well together and that the final required outcome is always achieved.
The data dependencies also allow StepFlow to generate user experiences. Included in the library is a basic HTML form generator. In the future more actions can be built for other platforms such as iOS and Android.
It is designed to be portable and currently has a Typescript and JavaScript helpers in addition to its native Rust support.
Getting Started
Basic concepts
Flows are both defined and executed within a Session
object. It is the main point of integration.
Execution
Once a session is defined, a flow only needs to call Session.advance
with any new data obtained.
Advancing exits the current step and enters the next step. An action is then called to fulfill the
data for the new step.
If data is lacking or invalid to either exit the current step or enter the next, the defined action will run on the current step again in hopes of obtaining the data successfully (i.e. user enters different data).
Defining
There are 3 parts to defining a flow:
Var. Variables define the data used in a Session. Types can be as basic as a String or more complex such as an Email. When paired with a
Value
, they are often stored in aStateData
structure.Step. This defines a single step (or screen) for a user. It allows a person to gradually work towards a final outcome rather than be faced with a single wall of required inputs. At a minimum a Step defines what it guarantees to output.
Action. Actions fulfill a Step's outputs. They can be interactive, such as a web form, or automated, such as an API call.
Example client-side flow
This example builds a simple client-side flow that runs in the browser.
Setup the build
Run the following commands in the terminal to get the build environment ready.
##
## SETUP THE BUILD
##
# create the directory
mkdir demo
cd demo
# install the basic dependencies
npm init -y
npm install --save-dev webpack webpack-cli stepflow-wasm html-webpack-plugin copy-webpack-plugin serve
Setup Webpack
We'll use Webpack to simplify building our HTML template. Note that we have our own WebAssembly loader so the Copy Plugin is used to copy the library to the output.
Create the webpack.config.js
file in your root directory.
//
// SETUP WEBPACK
//
// webpack.config.js
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
// generate an HTML file that loads index.js
new HtmlWebpackPlugin({
templateContent: '<form id="form"><div id="flow"></div><input type="submit" /></form>'
}),
new CopyPlugin({
patterns: [{from: "node_modules/stepflow-wasm/stepflow.wasm" }]
})
],
// optimize for developing
mode: "development",
devtool: "eval-source-map",
}
Define the user flow
We'll define our flow and session in the file src/index.js
.
Our simple flow is defined in a JSON format which is used to create
the Session.
//
// DEFINE THE USER FLOW
//
// src/index.js
const FLOW = {
// define the steps in the flow
steps: {
// the $root step is the parent for all steps
$root: {
// we'll have 2 steps in the flow: name and email
substeps: [ "name", "email" ],
// when we leave this step, we require these outputs to have been fulfilled
outputs: ["first_name", "last_name", "email"]
},
// define what the name and email steps output
"name": { outputs: ["first_name", "last_name"] },
"email": { outputs: ["email"] },
},
actions: {
// we'll use a single global action that generates an HTML form for each step's outputs
$all: {
type: "HtmlForm",
prefixHtml: "<label for='{{name}}'>{{name}}</label>", // each form entry will have a label
}
}
}
Run a Session
We can now create a Session and advance it until the flow is fully executed.
At the end, we're guaranteed that the required outputs have been gathered.
For this example, we'll use the HtmlFormSession
helper which is a light wrapper
on top of a Session
for HTML forms.
Add the example code to the end of src/index.js
.
//
// RUN A SESSION
//
// APPEND to src/index.js
import { loadStepflowWasm, attachFlowToHtmlForm } from "stepflow-wasm";
// load the WASM library
loadStepflowWasm("stepflow.wasm").then(stepFlowWasm => {
// the form element along with a child element to the generated form elements
const formElement = document.getElementById("form");
const anchorElement = document.getElementById("flow");
// create the HtmlFormSession
const formSession = attachFlowToHtmlForm(FLOW, stepFlowWasm, formElement, anchorElement);
// when done, show the user the data obtained
formSession.onFinish = (_formSession, data) => { alert(JSON.stringify(data))};
// advance to the first step
formSession.advance();
});
Try it out!
Finally, compile it with webpack with the command npx webpack
. You can then open
the compiled result in your browser using npx serve dist
.
JS/TS API Reference
JSON flow schema
Please look at the Typescript definition.
Session
todo!
HTML Form Session
todo!
Rust API Reference
Please start with docs.rs.
A server-side example using Warp and Tera templates can be found here