class UI::Form

Overview

A form view. Two usage modes co-exist:

  1. Sectioned form (existing iOS-style grouped semantics) — built via #add_section + adding Fields. Renders as grouped <fieldset>s on web; native renderers wrap each section in NSBox / iOS Form-section chrome.

  2. Flat form (Phase 8A) — built with form << child for simple sign-in / contact forms. Renders as inline flex-column children on web. Native renderers fall through to the section-rendering path unchanged; flat-children mode is web-only in Phase 8A.

Web POST semantics (Phase 8A)

When #action is non-nil, the web renderer wraps the form's children in <form action="..." method="POST"> and injects a hidden <input type="hidden" name="_csrf" value="..."> field. The CSRF token resolves in this order:

  1. Form#csrf_token explicit constructor arg (set once at build time).
  2. UI::RenderContext.csrf_token threaded into UI::Web::Renderer#render(view, render_context:).
  3. nil — the form still renders, but no hidden CSRF input is emitted.

Submit-button auto-promotion

On web, if #action is non-nil and the form contains exactly ONE UI::Button child whose type is the default Type::Button, the renderer promotes that single button to Type::Submit so a browser can submit the form. Multi-button forms do NOT auto-promote — set type: UI::Button::Type::Submit explicitly on the intended submitter.

Property mutation note: #csrf_token is read once by the web visit method on the live Form instance. Threading via the renderer's RenderContext is the supported API for shared trees. Direct post-build mutation of #csrf_token on a tree that may be re-rendered across requests is unsupported.

Defined in:

ui/views/form.cr

Constructors

Instance Method Summary

Instance methods inherited from class UI::View

accept(visitor : PlatformVisitor) accept, accessibility_label : String | Nil accessibility_label, accessibility_label=(accessibility_label : String | Nil) accessibility_label=, background : Color | Nil background, background=(background : Color | Nil) background=, blur_radius : Float64 blur_radius, blur_radius=(blur_radius : Float64) blur_radius=, border_color : Color | Nil border_color, border_color=(border_color : Color | Nil) border_color=, border_width : Float64 border_width, border_width=(border_width : Float64) border_width=, clip_to_bounds : Bool clip_to_bounds, clip_to_bounds=(clip_to_bounds : Bool) clip_to_bounds=, container_query(name : String) : self container_query, container_query_name : String | Nil container_query_name, container_query_name=(container_query_name : String | Nil) container_query_name=, corner_radius : Float64 corner_radius, corner_radius=(corner_radius : Float64) corner_radius=, fill_screen! : self fill_screen!, fluid_height(min : String | Number, ideal : String | Number, max : String | Number) : self
fluid_height : UI::Fluid | Nil
fluid_height
, fluid_height=(fluid_height : UI::Fluid | Nil) fluid_height=, fluid_width(min : String | Number, ideal : String | Number, max : String | Number) : self
fluid_width : UI::Fluid | Nil
fluid_width
, fluid_width=(fluid_width : UI::Fluid | Nil) fluid_width=, hidden : Bool hidden, hidden=(hidden : Bool) hidden=, id : String | Nil id, id=(id : String | Nil) id=, maximum_height : Float64 | Nil maximum_height, maximum_height=(maximum_height : Float64 | Nil) maximum_height=, maximum_width : Float64 | Nil maximum_width, maximum_width=(maximum_width : Float64 | Nil) maximum_width=, minimum_height : Float64 | Nil minimum_height, minimum_height=(minimum_height : Float64 | Nil) minimum_height=, minimum_width : Float64 | Nil minimum_width, minimum_width=(minimum_width : Float64 | Nil) minimum_width=, opacity : Float64 opacity, opacity=(opacity : Float64) opacity=, padding : EdgeInsets padding, padding=(padding : EdgeInsets) padding=, root_fill : Bool root_fill, root_fill=(root_fill : Bool) root_fill=, shadow_color : Color | Nil shadow_color, shadow_color=(shadow_color : Color | Nil) shadow_color=, shadow_offset_x : Float64 shadow_offset_x, shadow_offset_x=(shadow_offset_x : Float64) shadow_offset_x=, shadow_offset_y : Float64 shadow_offset_y, shadow_offset_y=(shadow_offset_y : Float64) shadow_offset_y=, shadow_radius : Float64 shadow_radius, shadow_radius=(shadow_radius : Float64) shadow_radius=, swiftkit_state_handle : Pointer(Void) | Nil swiftkit_state_handle, swiftkit_state_handle=(swiftkit_state_handle : Pointer(Void) | Nil) swiftkit_state_handle=, test_id : String | Nil test_id, test_id=(test_id : String | Nil) test_id=

Constructor Detail

def self.new(*, action : String | Nil = nil, method : String = "POST", csrf_token : String | Nil = nil) #

[View source]

Instance Method Detail

def <<(child : View) : self #

Append a flat (non-sectioned) child. Used by the screen author for simple sign-in / contact forms where iOS-style section grouping isn't needed. Returns the form for chaining.


[View source]
def accept(visitor : PlatformVisitor) #
Description copied from class UI::View

Accept a platform visitor for rendering dispatch. Each concrete view type calls visitor.visit(self).


[View source]
def action : String | Nil #

Web POST target. When nil (default) the web visit does NOT wrap children in a <form> element and the form renders identically to its previous sectioned-only behavior. When non-nil the wrapper <form action="..." method="..."> emits and CSRF + submit-button plumbing engages.


[View source]
def action=(action : String | Nil) #

Web POST target. When nil (default) the web visit does NOT wrap children in a <form> element and the form renders identically to its previous sectioned-only behavior. When non-nil the wrapper <form action="..." method="..."> emits and CSRF + submit-button plumbing engages.


[View source]
def add_section(header : String | Nil = nil, footer : String | Nil = nil) : FormSection #

[View source]
def children : Array(View) #

Flat (non-sectioned) children appended via <<. Web visit renders these inline after the section chrome. Native visit (Phase 8A scope) ignores #children — only sections render natively.


[View source]
def children=(children : Array(View)) #

Flat (non-sectioned) children appended via <<. Web visit renders these inline after the section chrome. Native visit (Phase 8A scope) ignores #children — only sections render natively.


[View source]
def csrf_token : String | Nil #

CSRF token written to the hidden <input name="_csrf"> field. Set via the constructor at screen-build time. If left nil the renderer falls back to UI::RenderContext.csrf_token threaded through UI::Web::Renderer#render(view, render_context:). If both are nil no hidden CSRF input is emitted.


[View source]
def csrf_token=(csrf_token : String | Nil) #

CSRF token written to the hidden <input name="_csrf"> field. Set via the constructor at screen-build time. If left nil the renderer falls back to UI::RenderContext.csrf_token threaded through UI::Web::Renderer#render(view, render_context:). If both are nil no hidden CSRF input is emitted.


[View source]
def field_count : Int32 #

[View source]
def method : String #

HTTP method for the form wrapper. Defaults to POST. The web renderer normalizes to uppercase.


[View source]
def method=(method : String) #

HTTP method for the form wrapper. Defaults to POST. The web renderer normalizes to uppercase.


[View source]
def sections : Array(FormSection) #

[View source]
def sections=(sections : Array(FormSection)) #

[View source]