2

I'm trying to create an accessible form that shows placeholder text, but moves it above the input when the user types into the input.

I've made a start by styling the label so it appears like a placeholder (sitting 'inside' the input through absolute positioning) and can move upon action. My problem is that I don't know if I'll be able to target the label through css.

I'm using contact form 7 on wordpress, so the form is generated. I can add wrapper elements (like the span for the label) but can't remove the span around the input. So a css rule like input ~ label will not work here.

Any advice for either a non-css workaround or an effective css way to target this? If possible I'd like to keep the 'label' tag so the form meets the accessibility criteria.

My code:

form.wpcf7-form p {
    position: relative;
    width: 100%;
    min-height: 1px;
    padding-right: 7.5px;
    padding-left: 7.5px;
    flex: 0 0 50%;
    max-width: 50%;
}

form.wpcf7-form p label {
    width: 100%;
    position: relative;
}

form.wpcf7-form p label span.formlabel {
    position: absolute;
    top: .8rem;
    z-index: 10;
    left: 1rem;
}

.form-control {
    display: block;
    width: 100%;
    padding: .8rem 0.75rem;
    font-size: 1rem;
    line-height: 1.5;
    color: #495057;
    background-color: #5D5D5D;
    background-clip: padding-box;
    border: none;
    border-radius: 0.25rem;
    transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
<form method="post" class="wpcf7-form" novalidate="novalidate">

<p>
<label>
<span class="formlabel">Business Name</span>
<span class="wpcf7-form-control-wrap business-name">
<input type="text" name="business-name" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required form-control" aria-required="true" aria-invalid="false">
</span> 
</label> 
</p>

<p>
<label> 
  <span class="formlabel">First Name</span>
  <span class="wpcf7-form-control-wrap first-name">
  <input type="text" name="first-name" value="" size="40"   class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required form-control" aria-required="true" aria-invalid="false">
  </span> 
 </label> 
</p>

<p>
<label> 
<span class="formlabel">Last Name</span>
<span class="wpcf7-form-control-wrap last-name">
<input type="text" name="last-name" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required form-control" aria-required="true" aria-invalid="false">
</span> 
</label> </p>

<p>
<label> 
  <span class="formlabel">Your Telephone</span>
  <span class="wpcf7-form-control-wrap your-tel">
<input type="tel" name="your-tel" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-tel wpcf7-validates-as-required wpcf7-validates-as-tel form-control" aria-required="true" aria-invalid="false">
  </span> 
  </label> 
</p>

<p>
  <label> 
  <span class="formlabel">Your Email</span>
  <span class="wpcf7-form-control-wrap your-email">
  <input type="email" name="your-email" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-email wpcf7-validates-as-required wpcf7-validates-as-email form-control" aria-required="true" aria-invalid="false">
  </span> 
  </label> 
 </p>


<p><input type="submit" value="Place your request" class="wpcf7-form-control wpcf7-submit btn btn-primary"></p>

</form>
Anne
  • 111
  • 6
  • You can not do this using CSS, not with that HTML structure. Whatever you want to manipulate based on the input field’s current state, would have to be a sibling following _after_ the input field. You can not select “backwards” or “a level up” with current CSS, see https://stackoverflow.com/questions/1014861/is-there-a-css-parent-selector – CBroe May 11 '20 at 11:15
  • @CBroe In this case, **you can** with `focus-within`. – Paulie_D May 11 '20 at 11:26
  • @Paulie_D well yeah, using that, you can make the label move when the input has focus, yes - but usually you’d not want it to move back, if the user actually entered something, and moves to the next field. Any combinations with `input:valid` or similar will not work with this structure. – CBroe May 11 '20 at 11:29
  • Thank you both! I've decided to go with a different solution based around both those notes. Rather than moving the label, I've added a placeholder, placed the label above the input at all times, then hidden the label (with opacity settings). I've used focus-within to make the label visible when you click the input. The main aim is to show what's in the field when you enter information, so this achieves that purpose too. – Anne May 11 '20 at 14:27
  • @Anne would you mind to share your HTML and CSS with me? I'm searching for the same solution :) – Mario Sep 30 '21 at 09:32

1 Answers1

1

You can use focus-within to manage this

form.wpcf7-form p label:focus-within span.formlabel

etc,

form.wpcf7-form p {
  position: relative;
  width: 100%;
  min-height: 1px;
  padding-top: 1.8rem;
  padding-right: 7.5px;
  padding-left: 7.5px;
  flex: 0 0 50%;
  max-width: 50%;
}

form.wpcf7-form p label {
  width: 100%;
  position: relative;
}

form.wpcf7-form p label span.formlabel {
  position: absolute;
  top: .8rem;
  z-index: 10;
  left: 1rem;
  white-space: nowrap;
  color: white;
  transition: all 1s ease;
}

form.wpcf7-form p label:focus-within span.formlabel {
  top: -1.8rem;
  color: red;
}

.form-control {
  display: block;
  width: 100%;
  padding: .8rem 0.75rem;
  font-size: 1rem;
  line-height: 1.5;
  color: #495057;
  background-color: #5D5D5D;
  background-clip: padding-box;
  border: none;
  border-radius: 0.25rem;
  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
<form method="post" class="wpcf7-form" novalidate="novalidate">

  <p>
    <label>
<span class="formlabel">Business Name</span>
<span class="wpcf7-form-control-wrap business-name">
<input type="text" name="business-name" value="" size="40" class="wpcf7-form-control wpcf7-text wpcf7-validates-as-required form-control" aria-required="true" aria-invalid="false">
</span> 
</label>
  </p>

</form>
Paulie_D
  • 107,962
  • 13
  • 142
  • 161
  • Thank you for your code. Could you please tell me, how I can stop the label from going back down, when the input field is filled? I've found this js-fiddle https://jsfiddle.net/273ntk5s/2/ where they manage to do it with :not(focus):valid, but I can't manage to get this to work with your example. – Mario Sep 30 '21 at 09:07