aboutsummaryrefslogtreecommitdiff
path: root/examples/03-controlled-inputs/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'examples/03-controlled-inputs/README.md')
-rw-r--r--examples/03-controlled-inputs/README.md46
1 files changed, 46 insertions, 0 deletions
diff --git a/examples/03-controlled-inputs/README.md b/examples/03-controlled-inputs/README.md
index 297a3c7..dff4a76 100644
--- a/examples/03-controlled-inputs/README.md
+++ b/examples/03-controlled-inputs/README.md
@@ -1,3 +1,49 @@
![](./header.png)
# 03 Controlled Inputs
+
+The most common way to handle inputs and other state-holding elements is in a
+_controlled_ way. This means your app's model is the source of truth for that
+element's state, and you update that state based on user input or other events.
+
+This example shows what that means in practice. For any controlled input we need
+two things:
+
+- A field in our model (or a function to derive a value from the model) to use
+ as the input's `value` attribute.
+
+- A message variant to handle input events and update the model.
+
+```gleam
+ui.input([
+ // Input's value is fixed to the model's `value` field
+ attribute.value(model.value),
+ // Whenever the input changes, we send a `GotInput` message with the new value
+ event.on_input(GotInput)
+])
+```
+
+## Why is this beneficial?
+
+Central to Lustre's architecture is the idea that your model is the single source
+of truth for your application's UI. This opens up the door to things like serialising
+progam state to load in the future, time-travel debugging, and rehydrating your
+app's state from a server.
+
+It also gives you tighter control of when and how to update your UI in response
+to user input. In this example, we only update the model when the new input
+value is less than 10 characters long.
+
+```gleam
+case msg {
+ GotInput(value) -> {
+ let length = string.length(value)
+
+ case length <= model.max {
+ True -> Model(..model, value: value, length: length)
+ False -> model
+ }
+ }
+
+ ...
+```