Me!

TJ VanToll

Using Semantic Class Names to Show and Hide Elements

| Comments

Showing and hiding elements has the potential to get complicated in large applications.

As a small example, say you have the following form that both displays a user’s data as well as allows them to edit it:

<form>
    <fieldset>
        <legend>Account Information</legend>
        
        <div>
            <label for="name">Name:</label>
            <input type="text" id="name" value="TJ" required>
            <span class="display">TJ</span>
        </div>
        <div>
            <label for="email">Email:</label>
            <input type="email" id="email" value="tj@somedomain.com" required>
            <span class="display">tj@somedomain.com</span>
        </div>
        <div class="actions">
            <button type="button" class="edit">Edit</button>
            <button type="submit" class="save">Save</button>
            <button type="button" class="cancel">Cancel</button>
        </div>
    </fieldset>
</form>

Without any logic both states of the form display:

Initial form display Open in New Window

Adding the Logic

Here’s the goal. The Edit button should:

  • Show the <input>s.
  • Show the Save button.
  • Show the Cancel button.
  • Hide the Edit button.
  • Hide the text in the <span>s.

The Cancel button should then undo these changes.

The traditional approach to this problem is to show and hide elements explicitly in JavaScript:

$( ".edit" ).on( "click", function() {
    $( ".display, .edit" ).hide();
    $( ".cancel, .save, input" ).show();
});
$( ".cancel" ).on( "click", function() {
    $( ".display, .edit" ).show();
    $( ".cancel, .save, input" ).hide();
});

To get the initial state of the form correct you also need some CSS:

.cancel, .save, input {
    display: none;
}

Because the list of elements has to be specified in JavaScript and CSS, this logic will be difficult to maintain. And this is for a trivial example; usually requirements are much more complex.

How can we make this better?

Semantic Class Names

Instead of targeting individual elements in JavaScript, let’s add a class name to the parent element that makes the most sense, in this case, the <form>:

$( ".edit" ).on( "click", function() {
    $( this ).parents( "form" ).addClass( "editing" );
});
$( ".cancel" ).on( "click", function() {
    $( this ).parents( "form" ).removeClass( "editing" );
});

Since the logic is simple, this can be written library-free as well (note classList is not available in IE < 10):

(function() {
    var form = document.querySelector( "form" ),
        editButton = document.querySelector( ".edit" ),
        cancelButton = document.querySelector( ".cancel" );

    editButton.addEventListener( "click", function() {
        form.classList.add( "editing" ); 
    });
    cancelButton.addEventListener( "click", function() {
        form.classList.remove( "editing" ); 
    });
}());

Advantages of Using Semantic Classes

There are 2 major advantages to this approach.

1) All display logic is now handled in CSS:

.cancel, .save, input {
    display: none;
}
.editing .save,
.editing .cancel,
.editing input {
    display: inline-block;
}
.editing .edit,
.editing .display {
    display: none;
}

2) You have a styling hook that can be used to make further changes to the display. For example, you might want to bold the labels when editing:

.editing label {
    font-weight: bold;
}

The final display of the form looks like this:

Semantic class approach Open in New Window

Conclusion

This is not a technique that I came up with but I’ve used it successfully in several large applications and have found that it scales well over time.

Do you have any other tricks you use to show & hide elements? If so, let me know in the comments.

Comments