Hi folks, here is my latest contribution to this component: Flatpickr with support for an unused feature from Phoenix.
attr :id, :string, required: true
attr :field, Phoenix.HTML.FormField,
doc: "a form field struct retrieved from the form, for example: @form[:email]"
attr :label, :string, default: nil
attr :class, :string, default: nil
def datetime_picker(%{field: %Phoenix.HTML.FormField{} = field} = assigns) do
errors = if Phoenix.Component.used_input?(field), do: field.errors, else: []
assigns = assign(assigns, :errors, Enum.map(errors, &translate_error(&1)))
~H"""
<div id={@id} class={["fieldset mb-2", not Enum.empty?(@errors) && "with-error"]}>
<div>
<label :if={@label} for={@field.id} class="label mb-1">{@label}</label>
<div id={"#{@field.id}-picker"} class="relative" phx-hook=".Flatpickr" phx-update="ignore">
<input
type="datetime-local"
name={@field.name}
id={@field.id}
placeholder="dd/mm/yyyy hh:mm"
value={normalize_iso_datetime(@field.value)}
class={[@class || "input w-full", @errors != [] && "input-error"]}
/>
</div>
<p :for={msg <- @errors} class="text-error mt-1.5 flex items-center gap-2 text-sm">
<.icon name="hero-exclamation-circle" class="size-5" />
{msg}
</p>
</div>
</div>
<script :type={Phoenix.LiveView.ColocatedHook} name=".Flatpickr">
import flatpickr from "flatpickr";
/**
* @type {import("phoenix_live_view").ViewHook & { picker: flatpickr.Instance }}
*/
export default {
mounted() {
const input = this.el.querySelector("input")
const originalType = input.getAttribute("type")
this.picker = flatpickr(input, {
enableTime: true,
altFormat: "d/m/Y H:i",
dateFormat: "Z",
minuteIncrement: 1,
time_24hr: true,
altInput: true,
static: true,
})
input.setAttribute("type", originalType);
input.setAttribute("style", "display: none;");
},
destroyed() {
this.picker.destroy()
this.picker = null
},
}
</script>
"""
end
This assumes that you are using Flatpickr with npm and the latest Phoenix/LiveView version.






















