JSON Input
v0.0.10
mix mishka.ui.gen.headless json_input
Overview of the Phoenix and LiveView Headless JSON Input Component
The Mishka Chelekom Headless JSON Input is a textarea for editing JSON in Phoenix and LiveView forms. It renders one textarea with spellcheck="false" and no styling. It does not parse or format anything in the browser. The server decodes the text, for example with Jason.decode/1, and sends the result back through value.
Set invalid to add aria-invalid="true" and data-invalid, then style the error state with data-[invalid]: variants. name, value, placeholder, rows (6 by default) and disabled are declared attributes. Other textarea attributes pass through: required, readonly, maxlength, minlength, cols, wrap, autocomplete, form and bindings such as phx-change. The root carries chelekom-json-input and takes class.
Base UI JSON Input example - JSON in a textarea (Phoenix headless)
Base UI JSON Input example - JSON in a textarea (Phoenix headless)
<.json_input
id="baseui-json-input"
value={~s({\n "name": "Mishka",\n "ok": true\n})}
rows={4}
class="w-full max-w-72 rounded-md border border-neutral-300 bg-white p-2 font-mono text-sm text-neutral-900 outline-none focus:ring-2 focus:ring-neutral-400 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-100"
/>JSON Input example - invalid state (Phoenix headless)
JSON Input example - invalid state (Phoenix headless)
The JSON could not be parsed.
<div class="flex flex-col gap-2">
<.json_input
id="invalid-json-input"
value={~s({\n "name": "Mishka",\n})}
rows={3}
invalid
class="w-full max-w-72 rounded-md border border-neutral-300 bg-white p-2 font-mono text-sm text-neutral-900 outline-none focus:ring-2 focus:ring-neutral-400 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-100 data-[invalid]:border-red-500 data-[invalid]:ring-2 data-[invalid]:ring-red-500/30"
/>
<p class="text-sm font-medium text-red-600 dark:text-red-400">The JSON could not be parsed.</p>
</div>Validating on the server
Bind the field to a form and decode its value in the event handler. On success, store the pretty-printed text. On failure, keep what the user typed and set invalid.
<.form for={to_form(%{"json" => @value}, as: :json_form)} id="json-form" phx-submit="format">
<.json_input
id="json-field"
name="json_form[json]"
value={@value}
invalid={match?({:error, _}, @result)}
rows={7}
class="w-full rounded-md border border-neutral-300 bg-white p-2 font-mono text-sm outline-none focus:ring-2 focus:ring-neutral-400 data-[invalid]:border-red-500 data-[invalid]:ring-2 data-[invalid]:ring-red-500/30 dark:border-neutral-700 dark:bg-neutral-900"
/>
<button type="submit">Validate and format</button>
</.form>
<p :if={@result}>{elem(@result, 1)}</p>def handle_event("format", %{"json_form" => %{"json" => json}}, socket) do
case Jason.decode(json) do
{:ok, data} ->
{:noreply,
assign(socket, value: Jason.encode!(data, pretty: true), result: {:ok, "Valid JSON"})}
{:error, error} ->
{:noreply, assign(socket, value: json, result: {:error, Exception.message(error)})}
end
endParts & data attributes
The root is the textarea itself. It has aria-invalid and data-invalid only while invalid is set. There are no inner parts.
Accessibility
This is a native multiline WAI-ARIA textbox, so the browser's own keyboard behavior applies. Connect it to a visible label with a label element that points at its id, and show the error text next to the field, because aria-invalid alone does not say what is wrong.
Attributes
| Name | Type | Default | Values | Required | Description |
|---|---|---|---|---|---|
id
|
string
| — | — | No | Optional unique id |
name
|
string
| — | — | No | Form field name |
value
|
string
| — | — | No | Current text |
placeholder
|
string
| — | — | No | Placeholder |
rows
|
integer
|
6
| — | No | Visible rows |
disabled
|
boolean
|
false
| — | No | Disable input |
invalid
|
boolean
|
false
| — | No | Reflects aria-invalid + data-invalid for error styling |
class
|
any
| — | — | No | Extra classes |
rest
|
global
| — | — | No | Any textarea/global attrs, e.g. phx-change, required |
Options
Each option takes one or more of its values, separated by commas.
| Option | Values |
|---|---|
--type
|
json_input
|
--module
| A module name of your own |
What it generates
mix mishka.ui.gen.headless json_input