Use label as a placeholder that move above the input when focused

Couldn't make a pure CSS version because of the way rails generates its errors (it add `<span />` over the element, either `input` or `label`, itself)
This commit is contained in:
Jean-Baptiste Bellet
2022-12-13 14:53:40 +01:00
parent 988dcc6081
commit 93e736fdf6
4 changed files with 86 additions and 32 deletions

View File

@@ -6,14 +6,14 @@
= t("split_checkout.step1.contact_information.title")
.two-columns-inputs
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
= f.label :email, t("split_checkout.step1.contact_information.email.label")
= f.text_field :email, { placeholder: t("split_checkout.step1.contact_information.email.placeholder") }
= f.text_field :email, { placeholder: " " }
= f.error_message_on :email
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
= bill_address.label :phone, t("split_checkout.step1.contact_information.phone.label")
= bill_address.text_field :phone, { placeholder: t("split_checkout.step1.contact_information.phone.placeholder") }
= bill_address.text_field :phone, { placeholder: " " }
= f.error_message_on "bill_address.phone"
%div.checkout-substep
@@ -22,34 +22,34 @@
= t("split_checkout.step1.billing_address.title")
.two-columns-inputs
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
= bill_address.label :firstname, t("split_checkout.step1.billing_address.first_name.label")
= bill_address.text_field :firstname, { placeholder: t("split_checkout.step1.billing_address.first_name.placeholder") }
= bill_address.text_field :firstname, { placeholder: " " }
= f.error_message_on "bill_address.firstname"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label" }
= bill_address.label :lastname, t("split_checkout.step1.billing_address.last_name.label")
= bill_address.text_field :lastname, { placeholder: t("split_checkout.step1.billing_address.last_name.placeholder") }
= bill_address.text_field :lastname, { placeholder: " " }
= f.error_message_on "bill_address.lastname"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= bill_address.label :address1, t("split_checkout.step1.address.address1.label")
= bill_address.text_field :address1, { placeholder: t("split_checkout.step1.address.address1.placeholder") }
= bill_address.text_field :address1, { placeholder: " " }
= f.error_message_on "bill_address.address1"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= bill_address.label :address2, t("split_checkout.step1.address.address2.label")
= bill_address.text_field :address2, { placeholder: t("split_checkout.step1.address.address2.placeholder") }
= bill_address.text_field :address2, { placeholder: " " }
= f.error_message_on "bill_address.address2"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= bill_address.label :city, t("split_checkout.step1.address.city.label")
= bill_address.text_field :city, { placeholder: t("split_checkout.step1.address.city.placeholder") }
= bill_address.text_field :city, { placeholder: " " }
= f.error_message_on "bill_address.city"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= bill_address.label :zipcode, t("split_checkout.step1.address.zipcode.label")
= bill_address.text_field :zipcode, { placeholder: t("split_checkout.step1.address.zipcode.placeholder") }
= bill_address.text_field :zipcode, { placeholder: " " }
= f.error_message_on "bill_address.zipcode"
%div{ "data-controller": "dependent-select", "data-dependent-select-options-value": countries_with_states }
@@ -112,24 +112,24 @@
%div{"data-shippingmethod-target": "shippingMethodAddress", style: "display: #{!display_ship_address || shipping_and_billing_match?(@order) ? 'none' : 'block'}" }
= f.fields :ship_address, model: @order.ship_address do |ship_address|
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= ship_address.label :address1, t("split_checkout.step1.address.address1.label")
= ship_address.text_field :address1, { placeholder: t("split_checkout.step1.address.address1.placeholder") }
= ship_address.text_field :address1, { placeholder: " " }
= f.error_message_on "ship_address.address1"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= ship_address.label :address2, t("split_checkout.step1.address.address2.label")
= ship_address.text_field :address2, { placeholder: t("split_checkout.step1.address.address2.placeholder") }
= ship_address.text_field :address2, { placeholder: " " }
= f.error_message_on "ship_address.address2"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= ship_address.label :city, t("split_checkout.step1.address.city.label")
= ship_address.text_field :city, { placeholder: t("split_checkout.step1.address.city.placeholder") }
= ship_address.text_field :city, { placeholder: " " }
= f.error_message_on "ship_address.city"
%div.checkout-input
%div.checkout-input.with-floating-label{ "data-controller": "floating-label"}
= ship_address.label :zipcode, t("split_checkout.step1.address.zipcode.label")
= ship_address.text_field :zipcode, { placeholder: t("split_checkout.step1.address.zipcode.placeholder") }
= ship_address.text_field :zipcode, { placeholder: " " }
= f.error_message_on "ship_address.zipcode"
%div{ "data-controller": "dependent-select", "data-dependent-select-options-value": countries_with_states }

View File

@@ -0,0 +1,30 @@
import { Controller } from "stimulus";
export default class extends Controller {
connect() {
const input = this.element.querySelector("input");
input.addEventListener("focus", this.focus.bind(this));
input.addEventListener("blur", this.blur.bind(this));
if (input.value.length > 0) {
this.focus();
}
const label = this.element.querySelector("label");
// Add transition class to the label and display the label
// after a short delay to avoid flickering
setTimeout(() => {
label.classList.add("with-transition");
label.style.display = "block";
}, 100);
}
focus() {
this.element.classList.add("active");
}
blur(e) {
if (e.target.value.length === 0) {
this.element.classList.remove("active");
}
}
}

View File

@@ -331,3 +331,35 @@
}
}
}
// Shows label as a placeholder, inside the input and when the input is focused shows the label above the input
.checkout-input.with-floating-label {
position: relative;
label {
display: none; // Display none by default, and shown by floating_label_controller
position: absolute;
top: 0;
left: 0;
font-size: 0.875rem;
padding: 8px;
padding-left: 9px;
color: $min-accessible-grey;
pointer-events: none;
transform: translateY(0);
transform-origin: top left;
&.with-transition {
transition: all 0.2s ease-in-out;
}
}
&.active {
label {
transform: translateY(-9px) translateX(10px) scale(0.9);
background-color: white;
padding-left: 3px;
padding-right: 3px;
padding-top: 0;
padding-bottom: 0;
}
}
}

View File

@@ -1919,33 +1919,25 @@ en:
title: Contact information
email:
label: Email
placeholder: e.g. Janedoe@email.com
phone:
label: Phone number
placeholder: e.g. 07987654321
billing_address:
title: Billing address
first_name:
label: First Name
placeholder: e.g. Jane
last_name:
label: Last Name
placeholder: e.g. Doe
address:
address1:
label: Address (Street + House Number)
placeholder: e.g. Flat 1 Elm apartments
address2:
label: Additional address info (optional)
placeholder: e.g. Cavalier avenur
city:
label: City
placeholder: e.g. London
state_id:
label: State
zipcode:
label: Postcode
placeholder: e.g. SW11 3QN
country_id:
label: Country
shipping_info: