Packages
noora
0.44.2
0.85.0
0.84.1
0.84.0
0.83.2
0.83.1
0.83.0
0.82.7
0.82.6
0.82.5
0.82.4
0.82.3
0.82.2
0.82.1
0.82.0
0.81.4
0.81.3
0.81.2
0.81.1
0.81.0
0.80.1
0.80.0
0.79.1
0.79.0
0.78.1
0.78.0
0.77.4
0.77.3
0.77.2
0.77.1
0.77.0
0.76.0
0.75.0
0.74.0
0.73.0
0.72.0
0.71.0
0.70.0
0.69.1
0.69.0
0.68.0
0.67.0
0.66.0
0.65.0
0.64.2
0.64.1
0.64.0
0.63.2
0.63.1
0.63.0
0.62.0
0.61.0
0.60.0
0.59.0
0.58.0
0.57.0
0.56.1
0.56.0
0.55.0
0.54.0
0.53.1
0.53.0
0.52.1
0.52.0
0.51.0
0.50.1
0.50.0
0.49.0
0.48.0
0.47.0
0.46.0
0.45.0
0.44.3
0.44.2
0.44.1
0.44.0
0.43.0
0.42.0
0.41.0
0.40.6
0.40.5
0.40.4
0.40.3
0.40.2
0.40.1
0.40.0
0.39.1
0.39.0
0.38.0
0.37.0
0.36.0
0.35.0
0.34.0
0.33.0
0.32.1
0.32.0
0.31.0
0.30.0
0.29.2
0.29.1
0.29.0
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.0
0.26.1
0.26.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.1
0.22.0
0.21.0
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.1
0.6.0
0.5.1
0.5.0
0.4.0
0.3.2
0.3.1
0.3.0
0.2.2
0.2.0
0.1.0
0.1.0-rc.2
0.1.0-rc.1
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
A component library for Phoenix LiveView applications
Current section
Files
Jump to
Current section
Files
lib/noora/text_area.ex
defmodule Noora.TextArea do
@moduledoc """
Renders textarea components with customizable labels, placeholders, character counting, and event handling.
## Example
```elixir
<.text_area name="description" label="Description" placeholder="Enter description" />
<.text_area name="message" label="Message" required={true} show_required={true} />
<.text_area name="notes" label="Notes" hint="Additional information" />
<.text_area name="content" label="Content" max_length={500} />
```
"""
use Phoenix.Component
import Noora.HintText
import Noora.Label
alias Phoenix.HTML.FormField
alias Phoenix.LiveView.JS
attr(:id, :string, required: false)
attr(:field, FormField, doc: "A Phoenix form field")
attr(:label, :string, default: nil, doc: "Label to be rendered above the textarea.")
attr(:sublabel, :string, default: nil, doc: "Sublabel to be rendered above the textarea.")
attr(:hint, :string, default: nil, doc: "Hint text to be rendered below the textarea.")
attr(:hint_variant, :string, default: "default", doc: "Hint text variant.")
attr(:error, :string, doc: "Errors to be rendered below the textarea. Takes precedence over `hint`.")
attr(:show_error_message, :boolean,
default: true,
doc: "Whether to show the error message below the textarea."
)
attr(:name, :string, doc: "The name of the textarea")
attr(:value, :string, doc: "The value of the textarea")
attr(:placeholder, :string, default: nil, doc: "Placeholder text to be rendered in the textarea.")
attr(:required, :boolean, default: false, doc: "Whether the textarea is required.")
attr(:show_required, :boolean, default: false, doc: "Whether the required indicator is shown.")
attr(:rows, :integer, default: 4, doc: "Number of visible text lines for the textarea.")
attr(:max_length, :integer, default: 200, doc: "Maximum number of characters allowed.")
attr(:show_character_count, :boolean, default: true, doc: "Whether to show the character count.")
attr(:resize, :string,
values: ~w(none both horizontal vertical),
default: "vertical",
doc: "CSS resize property for the textarea."
)
attr(:disabled, :boolean, default: false, doc: "Whether the textarea is disabled.")
attr(:rest, :global)
def text_area(%{field: %FormField{} = field} = assigns) do
assigns
|> assign(field: nil, id: Map.get(assigns, :id, field.id))
|> assign_new(:name, fn -> field.name end)
|> assign_new(:value, fn -> field.value end)
|> assign_new(:error, fn ->
field.errors |> Enum.map(fn {message, _opts} -> message end) |> List.first()
end)
|> text_area()
end
def text_area(assigns) do
assigns =
assigns
|> assign_new(:value, fn -> "" end)
|> assign_new(:error, fn -> nil end)
|> assign_new(:id, fn -> "text-area-#{System.unique_integer([:positive])}" end)
character_count = String.length(assigns.value || "")
resize = if assigns.disabled, do: "none", else: assigns.resize
assigns =
assigns
|> assign(:character_count, character_count)
|> assign(:resize, resize)
~H"""
<div class="noora-text-area" data-error={@error} disabled={@disabled}>
<.label
:if={@label}
label={@label}
sublabel={@sublabel}
required={@required and @show_required}
disabled={@disabled}
data-part="label"
/>
<div data-part="wrapper" phx-click={JS.focus(to: "##{@id}")}>
<textarea
id={@id}
name={@name}
rows={@rows}
required={@required}
placeholder={@placeholder}
maxlength={@max_length}
style={"resize: #{@resize}"}
disabled={@disabled}
{@rest}
>{@value}</textarea>
<span :if={@show_character_count && !@disabled} data-part="character-count">
{@character_count}/{@max_length}
</span>
</div>
<.hint_text :if={!is_nil(@error) and @show_error_message} label={@error} variant="destructive" />
<.hint_text :if={is_nil(@error) and @hint} label={@hint} variant={@hint_variant} />
</div>
"""
end
end