Flickr-Style Dynamic Edit Fields with jQuery and CSS3

The typical Flickr interface design includes a lot of Ajax panels which you can edit right from any settings page. Their website layout incorporates many web 2.0 trends as you move from account settings to photo settings and uploads. There are plenty of resources we could look at, and in this tutorial I’d like to focus on one specific entity.

We can build a set of small dynamic photos with a title and description. Then using jQuery we can target whenever a user clicks on these fields to edit the content right from the page. It’s a beautiful technique for creating a sleek user experience with just a few blocks of code. I won’t be storing any of the content into a database, but tying into a backend PHP script would make that process easy enough to accomplish.

Flickr-style demo preview Ajax fields

Live DemoDownload Source Code

Core Page Content

In the main HTML file I’m using a typical HTML5 doctype with a reference to the jQuery 1.7.2 library. A lot of the document uses basic positioning with 2 images aligned per row.

I’m using a class .photobox which contains each individual photo element. Inside are all the internal elements we need like inputs and save/cancel buttons. These are hidden by default using CSS but we can change all the styles with jQuery. Below is an example of just one photo box element.

<div id="p1" class="photobox">
  <a href=""><img src="images/farm-photo-filter-effects.png" alt="image #1"></a>
  <h4 class="title">Cavalinho Horse</h4>
  <p class="desc">Click to add a description</p>
  <input type="text" name="title" value="Cavalinho Horse" class="onefield">
  <textarea name="desc" class="textfield">Click to add a description</textarea>
  <a href="#" class="save">Save</a> <a href="#" class="cancel">Cancel</a>

There are other script methods where you can dynamically append new input fields onto the page after a user would click to edit. But I find this to be very clunky when you’re making multiple edits on the same page element, and so hiding the form fields is a much safer alternative. Plus we have all the DOM elements loading at the same time which is more typical behavior.

Dynamic Content Boxes

I want to jump right into the jQuery code so we can understand how these elements are manipulated. I’ve created an external script.js file which contains multiple event handlers.

$(".title, .desc").hover(function(){
  var previtem = $(this).prev();
  if(previtem.attr("class") == "title") {
  } else {
  }, function() {
    // on hover off
    var currenttag = $(this).prop("tagName");
    if(currenttag == "H4"){
    else {
}); // end title/desc hover event

This first block of code handles any hover event over the title and description blocks. This will turn the background into a bright yellow which indicates you have the ability to edit these fields. On the return function we’re dealing with the hover off state after a user moves their mouse away from the elements.

It’s a simple process to remove the highlight classes for this event. This particular event handler does have a lot of code because we’re compensating for both the title and description elements. When you hover over one of them the other also needs to be highlighted!

Processing the New Inputs

The next event handler we’re binding is on any click event targeting a title or description block. I’m using the jquery .on() event handler which immediately binds to the DOM elements unlike .live() which is always active listening over the whole page.

One particularly interesting method I’m using is .prop() to pull out the currently selected tag name. When we have a user clicking either the title or description we need to know which one to appropriately edit the alternative. We can accomplish this using an if/else statement and checking if the current element is an H4 heading or not.

$(".title, .desc").on("click", function(){
  var currenttag = $(this).prop("tagName");
  var titletag;
  var desctag;
  var titlevalue;
  var descvalue;
  if(currenttag == "H4") {
    titletag = $(this);
    desctag  = $(this).next();
    titlevalue = $(this).html();
    descvalue  = desctag.html();
  } else {
    titletag = $(this).prev();
    desctag  = $(this);
    titlevalue = titletag.html();
    descvalue  = $(this).html();
  titletag.css("display", "none");
  desctag.css("display", "none");

  $(this).siblings(".onefield").css("display", "block");
  $(this).siblings(".textfield").css("display", "block");
  $(this).siblings("a").css("display", "inline-block");
});	// end title/desc click event

Also the last few lines of code are how we change between static content and input fields. Regardless of which element the user clicks we need to hide both the title and description, then display the siblings which immediately follow.

I’m targeting the individual input fields by their class names. However for the two anchor links I’ve simply used $(this).siblings(“a”) as the selector. Since we have no other anchor links inside the photo box it’s a much safer and easier route than also using their classes.

Handling Save & Cancel Requests

The final major portion to our script is handling any saved changes. I’m using .live() for these buttons since they’re hidden by default, yet we want them to still be recognized in the DOM regardless. Also I’m passing the click event as a parameter so we can use e.preventDefault() which stops the href value from being loaded.

$(".save").live("click", function(e){
  var titleval = $(this).prevAll(".onefield:first").val();
  var descval  = $(this).prevAll(".textfield:first").val();

  var titlecontainer = $(this).siblings(".title");
  var desccontainer  = $(this).siblings(".desc");

  titlecontainer.html(titleval).css("display", "block");
  desccontainer.html(descval).css("display", "block");

  $(this).prevAll(".onefield:first").css("display", "none");
  $(this).prevAll(".textfield:first").css("display", "none");

  $(this).next(".cancel").css("display", "none");
  $(this).css("display", "none");
}); // end save btn click event

This first handler is called whenever a user clicks to save the changes they’ve made. The first two variables hold the current value of each text field which should be the new values we want to display on the page. The 2nd set of variables targets the containers for the title and description elements, even though they’re currently hidden.

What I’m doing is changing the CSS display properties for these title/desc elements while also appending the new values with .html() all in the same line of code. This is called chaining and it’s very common with jQuery development. We also hide the input fields and buttons as they are when the page first loads.

$(".cancel").live("click", function(e){

  var titlecontainer = $(this).siblings(".title");
  var desccontainer  = $(this).siblings(".desc");

  titlecontainer.css("display", "block");
  desccontainer.css("display", "block");

  $(this).prevAll(".onefield:first").val(titlecontainer.html()).css("display", "none");
  $(this).prevAll(".textfield:first").val(desccontainer.html()).css("display", "none");		
  $(this).prev(".save").css("display", "none");
  $(this).css("display", "none");
}); // end cancel btn click event

The live handler for the cancel button also passes the event parameter and stops any href value from loading into the browser. Also we’re setting up similar target variables, except now we just want to cancel any changes and keep the values we had before. The input fields are now chained with a CSS display property change, and also a change to the .val() internal input value.

I’m grabbing the original content inside our title/description containers and re-applying them to the input fields. That way after you hit cancel and go back to edit again the field values will reset and you won’t see any changes made previously.

Flickr-style demo preview Ajax fields

Live DemoDownload Source Code

Final Thoughts

I hope this tutorial can introduce some of the more complex actions in jQuery to interested web developers. My code isn’t overly difficult in that even a novice JavaScript developer could figure out the key points. All of the code should be supported by current standards in web design, which is great for almost all modern web browsers.

If you really love this guide then definitely check out the live demo and see how it stacks up to your own code. Alternatively you can download a copy of my source code and use that for your own practice, or even include it onto your live website. The code paradigms are very fluid and can easily transition from one website to the next. If you have any additional thoughts or questions feel free to share with us in the post discussion area below.