Phoenix 1.7 で 導入された CoreComponent
モジュールに input 関数コンポーネントがあります。mix phx.new でPhoenix アプリを生成してすぐに使え、いい感じにinput 要素がスタイリングされて便利です。
しかしながら、自分でDaisyUI等を使用してinput 要素をスタイリングをしたいときに不都合が生じます。input 関数コンポーネントのCSSは直書きされており、関数呼び出し時に指定することができないのです。
対策は、2つ考えられます。
- input 関数コンポーネントに直書きされたCSSを好きなように調整
-
input 関数コンポーネント実行時に
class
属性を渡せるようにする
ここでは後者をやります。
やりかた
class
属性を受け取れるようにする
Phoenix.Component.attr/3マクロでclass
属性を明示します。型は:string
でもいいのですが、リストで渡したい時もあるので:any
としています。
attr :id, :any, default: nil
attr :name, :any
attr :label, :string, default: nil
attr :value, :any
attr :type, :string,
default: "text",
values: ~w(checkbox color date datetime-local email file month number password
range search select tel text textarea time url week)
attr :field, Phoenix.HTML.FormField,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :errors, :list, default: []
attr :checked, :boolean, doc: "the checked flag for checkbox inputs"
attr :prompt, :string, default: nil, doc: "the prompt for select inputs"
attr :options, :list, doc: "the options to pass to Phoenix.HTML.Form.options_for_select/2"
attr :multiple, :boolean, default: false, doc: "the multiple flag for select inputs"
+ attr :class, :any, default: nil
attr :rest, :global,
include: ~w(accept autocomplete capture cols disabled form list max maxlength min minlength
multiple pattern placeholder readonly required rows size step)
slot :inner_block
受け取ったclass
属性を反映させる
もともとあったclass
属性の値をdefault_class
に切り出します。
実行時にclass
属性が明示されている場合にはそれを優先するようにします。
# All other inputs text, datetime-local, url, password, etc. are handled here...
def input(assigns) do
+ default_class =
+ "mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6"
+
+ assigns = assign(assigns, class: assigns[:class] || default_class)
+
~H"""
<div phx-feedback-for={@name}>
<.label for={@id}><%%= @label %></.label>
<input
type={@type}
name={@name}
id={@id}
value={Phoenix.HTML.Form.normalize_value(@type, @value)}
class={[
- "mt-2 block w-full rounded-lg text-zinc-900 focus:ring-0 sm:text-sm sm:leading-6",
+ @class,
"phx-no-feedback:border-zinc-300 phx-no-feedback:focus:border-zinc-400",
@errors == [] && "border-zinc-300 focus:border-zinc-400",
@errors != [] && "border-rose-400 focus:border-rose-400"
]}
{@rest}
/>
<.error :for={msg <- @errors}><%%= msg %></.error>
</div>
"""
end
使い方
これでDaisyUIのclassを使えるようになりました!
<.input
field={@form[:name]}
placeholder="Name"
autocomplete="off"
class="input input-bordered input-secondary mr-2"
/>
あとはお好みで調整してください。
最後に一言
本記事は 闘魂 Elixir #72 の成果です。ありがとうございます。