JSON Input

v0.0.10

v0.0.10StableHeadlessStatelessAccessibleApache-2.0
Installation mix mishka.ui.gen.headless json_input
Source View Source

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)

heex
<.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.

heex
<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.

heex
<.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>
elixir
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
end

Parts & 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.