LaceySnr.com - Salesforce Development Posts by Matt Lacey

<lightning:input> Is Your New Best Friend!

Posted: 2017-04-27

An area of Lightning that still has room for development from a developer's perspective is the styling aspect. The Lightning Design System provides us with CSS, and the various aura and ui tags present us with some easy to use components, yet creating a UI that fits in with the rest of Lightning Experience can still take a bit of work. With Visualforce you could create a very standard UI simply by using the standard tags, if you wanted a look and feel consistent with the rest of the system it didn't take any extra effort. These days it's not hard per se, but it can be a little tricky.

<ui:inputXYZ> and Pals

If you visit the Lightning Design System page for forms, you'll see this example of an inline form:

An image of an example inline form

With an associated code snippet:

<form class="slds-form--inline">
  <div class="slds-form-element">
    <label class="slds-form-element__label" for="name">Name</label>
    <div class="slds-form-element__control">
      <input type="text" id="name" class="slds-input" />
    </div>
  </div>
  <div class="slds-form-element">
    <label class="slds-form-element__label" for="email">Email</label>
    <div class="slds-form-element__control">
      <input type="text" id="email" class="slds-input" />
    </div>
  </div>
  <div class="slds-form-element">
    <button type="button" class="slds-button slds-button--brand">Send</button>
  </div>
</form>

Seems easy enough. Now the <ui:inputText> and <ui:inputDate> elements have label properties, and they do generate label elements etc. in the output markup, but this code:

<form class="slds-form--inline">
 <div class="slds-form-element">
  <ui:inputDate aura:id="startDate" label="Start" class="field" value="{!v.rangeStart}" displayDatePicker="true"/>
 </div>
 <div class="slds-form-element">
  <ui:inputDate aura:id="endDate" label="End" class="field" value="{!v.rangeEnd}" displayDatePicker="true"/>
 </div>
</form>

Generates this form:

A form with labels above the input fields, not along side as should be the case

The problem here is the standard elements do not generate the classes used by the SLDS, meaning there's a disconnect that has to be handled by the developer.

The various <ui:inputXYZ> tags have two properties for CSS classes, labelClass and class, but even with these we can't reproduce the exact hierarchy specified for a slds-form-element specified in the example code: there's no way to set the slds-form-element__control for the <div> that wraps the actual HTML <input> tag in the generated markup. Instead we need to separate out the label ourselves, generating the rather verbose markup that most (if not all) of SLDS seems to require.

Enter <lightning:input>

Note: This tag is in beta, so test it carefully for your use case!

There's a new tag in town, and it's job is to make your life easier and close the gap. Upon reading the documentation you may even notice this little scrap of information:

This component inherits styling from forms in the Lightning Design System.

Pure gold, right?

Using this new tag the previous code can simply be replaced with this:

<form class="slds-form--inline">
 <div class="slds-form-element">
  <lightning:input aura:id="startDate" type="date" label="Start" name="startDate" value="{!v.rangeStart}"/>
 </div>
 <div class="slds-form-element">
  <lightning:input aura:id="endDate" type="date" label="End" name="endDate" value="{!v.rangeEnd}"/>
 </div>
</form>

which is definitely an improvement:

An image showing a correct inline form using the previous code snippet

One issue I did hitwas that the input fields didn't appear to reflect values set through the controller. My controller has an init function that sets values for these two date fields (see my previous entry here on how to format the value for date fields), and this was running but the elements did not update; I thought I was missing something and thanks to the comments from Kyle below, I got this resolved.

I was setting the dates as a String which is correct, but I wasn't adding leading zeros to the month or day components, i.e. I was specifying "2017-4-1" and it needs to be in the format "2017-04-01". Given that I talked about leading zeroes in my previous post on Lightning and Date objects you'd think I'd have noticed this, but alas, programming is programming and you'll learn some things many times over before they actually stick.

Required Means Required!

One final note, the name and label properties of <lightning:input> are required, and if you omit one of them you'll find your component completely fails to load, so if you find yourself wondering why an error has suddenly reared it's ugly head, check for that as a first port of call.