Emerge.UI.Input (Emerge v0.2.1)

Copy Markdown View Source

Input element helpers.

Emerge.UI.Input provides the two main interactive element constructors:

  • text/2 for editable single-line text input
  • multiline/2 for auto-growing multiline text input
  • button/2 for button-like interaction around any single child element

These helpers provide input behavior, not default visuals. Style them with the same attrs you would use on other elements, such as Emerge.UI.Background, Emerge.UI.Border, Emerge.UI.Font, and Emerge.UI.Interactive.

Text Input

text/2 builds a single-line text input element. multiline/2 builds a multiline text input that defaults to a one-line minimum height and grows with its content when height is omitted.

Both helpers are controlled inputs: the second argument is the currently rendered string value. Runtime editing can update the focused session immediately, but the next render still comes from the value you pass in.

For both text-input helpers, a matching Emerge.UI.Event.on_key_down/2 handler suppresses the default keydown behavior for that input. For example, on_key_down(:a, ...) suppresses inserting "a", and on_key_down(:enter, ...) can suppress the default newline insertion in multiline/2.

Pair it with Emerge.UI.Event.on_change/1 when you want to receive updated values, and with Emerge.UI.Event.on_focus/1 or Emerge.UI.Event.on_blur/1 when you care about focus changes.

Buttons

button/2 wraps exactly one child element and gives it button-like interaction behavior.

The child can be any element tree, not just Emerge.UI.text/1. If you need a more complex button body, wrap multiple visual parts in Emerge.UI.row/2, Emerge.UI.column/2, or Emerge.UI.el/2 and pass that as the one child.

button/2 does not apply default styling. A typical button composes Emerge.UI.Event.on_press/1 with visual attrs such as padding, background, border radius, and interaction styles.

Examples

This render function builds a common form layout: a search field above a save button.

def render(state) do
  column([spacing(16)], [
    Input.text(
      [
        key(:search),
        width(px(240)),
        padding(12),
        Background.color(color(:white)),
        Border.rounded(8),
        Event.on_change(:search_changed)
      ],
      state.query
    ),
    Input.button(
      [
        padding(12),
        Background.color(color(:sky, 500)),
        Border.rounded(8),
        Font.color(color(:white)),
        Event.on_press(:save)
      ],
      text("Save")
    )
  ])
end

Summary

Types

t()

Input element returned by this module.

Functions

Build a button-like element with exactly one child.

Build a multiline text input.

Build a single-line text input.

Types

t()

@type t() :: Emerge.UI.element()

Input element returned by this module.

Functions

button(attrs, child)

@spec button(Emerge.UI.attrs(), Emerge.UI.child()) :: t()

Build a button-like element with exactly one child.

button/2 is unstyled. Compose it with attrs such as Emerge.UI.Event.on_press/1, Emerge.UI.Background.color/1, Emerge.UI.Border.rounded/1, and Emerge.UI.Interactive.mouse_down/1 to get the behavior and appearance you want.

The child can be any element tree. If you need multiple visual pieces inside the button, wrap them in a layout element and pass that layout as the one child.

Examples

This is a simple styled action button with pressed feedback.

Input.button(
  [
    padding(12),
    Background.color(color(:sky, 500)),
    Border.rounded(8),
    Font.color(color(:white)),
    Event.on_press(:save),
    Interactive.mouse_down([Transform.move_y(1)])
  ],
  text("Save")
)
# Wrap multiple visual parts in a layout element and pass that layout
# as the button's single child.
Input.button(
  [
    padding(10),
    Background.color(color(:slate, 100)),
    Border.rounded(8),
    Event.on_press(:open_menu)
  ],
  row([spacing(8)], [
    text("v"),
    text("Actions")
  ])
)

multiline(attrs, value)

@spec multiline(Emerge.UI.attrs(), String.t()) :: t()

Build a multiline text input.

value is the current content shown in the field. The element has no children.

Input.multiline/2 defaults to a minimum height of one text line. When no explicit height(...) attr is present, it grows vertically to fit its wrapped content. When you do provide height(...), the element remains multiline but stops auto-growing.

Like Input.text/2, pair it with Emerge.UI.Event.on_change/1 and treat the second argument as the source of truth for the currently rendered content.

Content wraps to the resolved width of the element.

By default, both Enter and Shift+Enter insert a newline.

A matching Emerge.UI.Event.on_key_down/2 suppresses the default multiline edit behavior for that keydown, including the normal Enter newline.

Example

This notes field auto-grows as its wrapped content expands.

def render(state) do
  Input.multiline(
    [
      key(:notes),
      width(fill()),
      padding(12),
      Background.color(color(:white)),
      Border.rounded(8),
      Event.on_change(:notes_changed)
    ],
    state.notes
  )
end

text(attrs, value)

@spec text(Emerge.UI.attrs(), String.t()) :: t()

Build a single-line text input.

value is the current content shown in the field. The element has no children.

Use Emerge.UI.Event.on_change/1 to receive updated values and treat the second argument as the source of truth for the currently rendered content.

A matching Emerge.UI.Event.on_key_down/2 suppresses the default single-line edit behavior for that keydown.

Example

This field keeps its rendered value in state.query and emits messages for change, focus, and blur.

def render(state) do
  Input.text(
    [
      key(:search),
      width(px(240)),
      padding(12),
      Background.color(color(:white)),
      Border.rounded(8),
      Event.on_change(:search_changed),
      Event.on_focus(:search_focused),
      Event.on_blur(:search_blurred)
    ],
    state.query
  )
end