SOLVED

Re: Display form label when text is within field

Go to solution
Tim_Marcacci
Level 2

Hi everyone,

I'm trying to build out a form where the labels hidden until a user types into that field and the label then appears above. Below is a screenshot of what I'm trying to do. The hint text is in place and everything is styled and good to go, I am just not familiar enough with javascript to get this to work (I'm assuming its a javascript solution?). Note that this needs to happen on a per-field basis. I don't want all field to appear when you start typing into just 1 field. Sanford Whiteman​, I know you're the go-to guy with this sort of javascript question.

Screen Shot 2018-11-22 at 7.04.33 AM.png

Any help would be great!

Thanks,

Tim

1 ACCEPTED SOLUTION
SanfordWhiteman
Level 10 - Community Moderator

Y'left out one important case with Marketo forms.

Also, you need only listen for the input event to cover both key events and clipboard events. See

     MktoForms2 :: Floating Labels (tmarcacci)

which is tested back to IE 10.

Also, note to Tim: the placeholders aren't great in IE 10-11 because they're the same white color as user-entered text:

pastedImage_0.png

View solution in original post

23 REPLIES 23
Jay_Jiang
Level 10

Using some jQuery

$(".mktoForm .mktoLabel").css('visibility','hidden');

$(".mktoForm :input").keyup(function(){

if($(this).val()!=""){

  $("label[for="+$(this).prop('name')+"]").css('visibility','visible')

} else {

  $("label[for="+$(this).prop('name')+"]").css('visibility','hidden')

}

})

/* // uncomment this if you care about people right clicking and CLICKING paste

$(".mktoForm :input").change(function(){

if($(this).val()!=""){

  $("label[for="+$(this).prop('name')+"]").css('visibility','visible')

} else {

  $("label[for="+$(this).prop('name')+"]").css('visibility','hidden')

}

})

*/

SanfordWhiteman
Level 10 - Community Moderator

Remember to constrain all selectors to only the current form element, or else the effect will be really bizarre.

Jay_Jiang
Level 10

MktoForms2.whenReady(function (form) {

    var formEl = form.getFormElem()[0];

    $(".mktoLabel" , formEl).css('visibility','hidden');

    function toggle(ele){

        if($(ele).val()!=""){

            $("label[for="+$(ele).prop('name')+"]" , formEl).css('visibility','visible') 

        } else { 

            $("label[for="+$(ele).prop('name')+"]" , formEl).css('visibility','hidden') 

        }

    }

    $(":input" , formEl).keyup(function(){toggle(this)}).change(function(){toggle(this)});

});

SanfordWhiteman
Level 10 - Community Moderator

Y'left out one important case with Marketo forms.

Also, you need only listen for the input event to cover both key events and clipboard events. See

     MktoForms2 :: Floating Labels (tmarcacci)

which is tested back to IE 10.

Also, note to Tim: the placeholders aren't great in IE 10-11 because they're the same white color as user-entered text:

pastedImage_0.png

TK
Level 1
Level 1

@SanfordWhiteman 

Stumbled across this resolution and it worked perfectly for me! Thanks so much!

 

Quick question:

 

Your snippet works as intended for me, but is there a way to add it so the label action also occurs when the input field is in focus?

SanfordWhiteman
Level 10 - Community Moderator

Your snippet works as intended for me, but is there a way to add it so the label action also occurs when the input field is in focus?

That functionality could be added, but it's unlikely I'll get to it anytime soon.

Tim_Marcacci
Level 2

Hi Sanford Whiteman Is there a way to isolate this floating label code to a specific form? This form will be living in the footer, so I don't want it to affect any other forms that may be on a page.

SanfordWhiteman
Level 10 - Community Moderator

Is there a way to isolate this floating label code to a specific form?

Sure, just compare to the form ID.

MktoForms2.whenReady(function(form){

  var formEl = form.getFormElem()[0],

      formId = form.getId(),

      enhanceableFormIds = [2200],

      placeholderableTypes = ["text", "search", "tel", "url", "email", "password", "number"];

  if (enhanceableFormIds.indexOf(formId) == -1) return;

  /* ... continue with the rest of your custom behaviors... */

Kyle_Hand
Level 1

Hey this is a great solution. Thanks for posting this up. Is there a way to include textareas for larger comment areas. Your code seems to include everything but textareas? Thanks in advance.

SanfordWhiteman
Level 10 - Community Moderator

Hey this is a great solution. Thanks for posting this up. Is there a way to include textareas for larger comment areas. Your code seems to include everything but textareas? Thanks in advance.

Grab the updated JS pane from v1.0.1: MktoForms2 :: Floating Labels (tmarcacci) v1.0.1

CaitlinKelley
Level 1

Hey Sanford,

This is a wonderful solution, thank you for sharing! I was wondering if you have any recommendations for how to create similar functionality on dropdown select fields? 

SanfordWhiteman
Level 10 - Community Moderator
The code could be adapted to detect whether the "no-value Option" (that's usually the top Option in a Marketo Select field) is chosen.

However, IIRC, Selects don't fire the Input event. So there you'd have to detect the Change event instead. It would take a little time to test and work out the kinks, definitely 100% possible.
Crystal_Pacheco
Level 4

@SanfordWhiteman This script is really great except that it's missing the ability to show/hide the label if a change has been made to the select drop down menu.
The textarea input field also required a small fix to get working. Here is what I have so far that works for textarea but not select:

MktoForms2.whenReady(function(form){
      var formEl = form.getFormElem()[0],
          placeholderableTypes = {
             "INPUT" : ["text", "search", "tel", "url", "email", "password", "number"],
             "TEXTAREA" : ["textarea"],
             "SELECT" : ["select"]
          };
      
      function managePlaceholders(knownTarget){
         var currentValues = form.getValues(),
             fieldNames = knownTarget ? [knownTarget.target.name] : Object.keys(currentValues);
         
         fieldNames
            .map(function(fieldName){
              var fieldEl = formEl.querySelector("[id='" + fieldName + "']" ),
                  labelEl = fieldEl && formEl.querySelector("label[for='" + fieldEl.id + "']" );
            
              return {
                 fieldEl : fieldEl,
                 labelEl : labelEl,
                 isValued : Boolean(currentValues[fieldName])
              }
            })
            .filter(function(labelDesc){
              return labelDesc.labelEl && 
                     Array.isArray(placeholderableTypes[labelDesc.fieldEl.nodeName]) &&
                     placeholderableTypes[labelDesc.fieldEl.nodeName]
                       .some(function(type){
                         return labelDesc.fieldEl.type == type;
                       });                     
            })
            .forEach(function(labelDesc){
              labelDesc.labelEl.setAttribute( "data-for-placeholder-hidden", [labelDesc.isValued, knownTarget ? "interactive" : "prefilled"].join("-") );
            });
      }
      
      formEl.addEventListener("change", managePlaceholders);
      managePlaceholders();
   });

 

SanfordWhiteman
Level 10 - Community Moderator

Well, your change broke the original functionality. input isn't the same as change, and the choice to use input was 100% deliberate.

 

As I mentioned above, the <select> element needs to use change (but not input), while <input> subtypes need to use input (but not change).

 

The code needs to be refactored to ensure that each fired event only pertains to its relevant subset of the element types. It's not changing just one line of code.

 

(P.S. The type of a <select> isn't select.)

Andy_Weilbaeche
Level 1

@SanfordWhiteman 

Thanks for all of your great solutions in the past!

 

Just an FYI that this solution gives a Medium severity vulnerability according to our Checkmarx report.

 

"The method toggle embeds untrusted data in generated output with $. This
untrusted data is embedded into the output without proper sanitization or encoding, enabling an attacker to inject
malicious code into the generated web-page."

 

Method function toggle(ele){
....
181.  $("label[for="+$(ele).prop('name')+"]" , 
formEl).css('visibility','hidden') 

 

I think the solution for me is to probably hardcode the field label names but I haven't gotten all of the way through it yet. Would make it substantially less dynamic but would remove the potential vulnerability.

 

Just dropping a line in this years-old thread!

Maybe you know how to overcome this?

SanfordWhiteman
Level 10 - Community Moderator

That’s not my code.

 

(It’s also probably a spurious warning based on the context, there’s absolutely no untrusted output generated there.)

Tim_Marcacci
Level 2

Thanks so much Sanford Whiteman​ and Jay Jiang​. I'll definitely fix the white placeholders in IE, but this functionality is perfect!  I'll also look into the the DoS vulnerability article as well.

Cheers.

SanfordWhiteman
Level 10 - Community Moderator

I'm away for Thanksgiving but will update tonight.

You should link to your form in progress, though.

Tim_Marcacci
Level 2

Thanks for your help, Sanford. I wan't expecting to hear from anyone on this thread until after the holiday, so please do enjoy your thanksgiving!

In the meantime, I have placed the form on a test page here: https://www.xifin.com/info/test-page-visualstrata-styled-form

SanfordWhiteman
Level 10 - Community Moderator

Not directly related to your question, but you're not using one of those DoS-vulnerable pre-fill methods on that page, are you?