An attempt for a more accessible edit-in-place solution

Today I will try to find a more accessible way to provide an edit-in-place script. The “solution described here”:http://icant.co.uk/sandbox/more-accessible-edit-in-place/index.html is probably not ready for real life yet, please test it in different environments and provide fixes. It is licenced with creative commons share-alike, so go nuts!

I really like the idea of edit-in-place. Probably the most used example of edit-in-place is flickr which allows you to click any heading or description when you are logged in to directly edit it. The reason I like edit-in-place is that it makes it a lot easier for users to describe things, which hopefully results in more accessible and easier to find web sites (after all text is what gets indexed and what is available to everybody). The drawback of edit-in-place is that a lot of solutions are not very accessible. They add a click handler to elements that are not necessarily available to assistive technology and are not at all accessible with a keyboard.

A non-scripting solution attempt

Technically the easiest solution to create an accessible edit-in-place would be to use input fields with labels and use CSS to make them look like the other elements. The code could be the following:


<h1 class="editable">
  <label for="mainheading">Heading:</label>
  <input type="text" id="mainheading" value="Otters in eastern Europe">
</h1>

And the CSS:


.editable label{
  position:absolute;
  top:0;
  left:-9999px;
}
.editable input{
  border:none;
  font-family:arial,sans-serif;
}

But alas! Is it more accessible? I am not sure, as the semantic goodness of a heading is disturbed. I am quite sure search engines will frown upon it and as screen readers work differently in forms mode than in reading mode it might even be more confusing. So let’s scratch that.

Making it work unobtrusively

The next step would be to use a normal heading and somehow connect it with a form field somewhere else in the document. The cool thing about this is that we have something like that in plain HTML: targeted links. For example:


<form id="editform" action="servermagic.php">
<h1 class="editable">
  <a href="#editheader">Edit me, wuss!</a>
</h1>
<p class="editable">
  <a href="#editdescription">Me as well, do it!</a>
</p>
<div id="editingsection">
  <p>
    <label for="editheader">Content of main heading:</label>
    <input type="text" id="editheader" name="editheader">
  </p>
  <p>
    <label for="editdescription">Content of description:</label>
    <input type="text" id="editdescription" name="editdescription">
  </p>
  <p><input type="submit" value="Save Changes"></p>
</div>
</form>

This works without JavaScript (but somehow my Firefox does not highlight the form field when you hit the link, does anyone know why? Please comment!). All it needs to turn it into a working version of edit-in-place is a JavaScript. What the script does is:

  • find the section with the ID “editsection” and hide it from view
  • find all elements with the class “editable” and add a click handler pointing to an edit function
  • override the submit event of the form to point to a store function

The edit function should do the following:

  • check if another element is already being edited and focus that if there is one
  • Get the ID of the form element from the href of the targeted link
  • set the value of the form element to the content of the element
  • set an “edited” style to the original element to hide it
  • show the form field where the original link was
  • focus the form field
  • tell the main script what element is currently being edited

The store function should:

  • check if there is an element edited (to avoid overriding normal form submission)
  • set the content of the targeted link to the value of the field
  • move the form field back to where it came from
  • set the focus back to the link
  • store the content asynchronously (not implemented here)
  • stop the normal form submission
  • reset the edit state of the script to none

Following is the script that does exactly that. I am using the YUI in this example as I like to concentrate on writing scripts rather than worrying about browser problems. That said, notice that you need to wrap form field focus in a timeout in Firefox, what’s with that?


YAHOO.namespace('ch');
YAHOO.ch.editinplace = function(){

  /* Names and IDs used */
  var namesandids = {
    editsection:'editingsection',
    edited:'edited',
    hidden:'hidden',
    editable:'editable',
    form:'editform'
  };

  var YE = YAHOO.util.Event,YD = YAHOO.util.Dom;

  var edit = {};
  var editingsection = YD.get(namesandids.editsection);
  if(editingsection){
    YD.addClass(editingsection,namesandids.hidden);

    function doedit(e){
      if(!edit.target){
        var t = YE.getTarget(e);
        if(t.href){
          var fieldid = t.getAttribute('href').split('#')[1];
          var field = YD.get(fieldid);
          this.appendChild(field);
          field.value = t.innerHTML;
          YD.addClass(t,namesandids.edited);
          setTimeout(function(){field.focus();},10)
          edit = {target:t,field:field,id:fieldid};
        };
      } else {
        setTimeout(function(){edit.field.focus();},10)
      }
      YE.preventDefault(e);
    };
    
    function store(e){
      if(edit.target){
        edit.target.innerHTML = edit.field.value;
        YD.removeClass(edit.target,namesandids.edited);
        editingsection.appendChild(edit.field);
        edit.target.focus();
        // Ajax Magic here, you can used edit.id as the id 
        YE.preventDefault(e);
        edit = {};
      };
    };

    var edits = YD.getElementsByClassName(namesandids.editable);
    YE.on(edits,'click',doedit);
    YE.on(YD.get(namesandids.form),'submit',store);

  }
}();

Try out the solution and Download the example page with the script as a zip and tell me what you think!

Tested in Firefox, IE7 and Opera 9 on PC, please get me some more feedback on other systems and browsers.

[tags]unobtrusive,accessibility,editinplace,interface[/tags]

Tags: , , ,

8 Responses to “An attempt for a more accessible edit-in-place solution”

  1. Frode Danielsen Says:

    Interesting solution! Tested it in Safari 3.0.4 in OS X 10.4, and it seems to mostly work. Only two glitches I’ve noticed:

    1. If I hit enter in the edit field, the form is submitted even though it seems your intention is to prevent it (and rather use AJAX).

    2. When the input field is blurred (and text saved), the text node itself gets a focus ring. This disappears if I click somewhere else on the page again or hit the tab key. It’s not a pure redraw bug in Safari, as resizing of the window does not clear the focus ring. Only “double blurring” seems to do it. (Screenshot: http://frode.danielsen.net/tmp/textfocus.png)

  2. Yoan Says:

    I would do:

    edit.target.parentNode.focus();

    instead of:

    edit.target.focus();

    focusing the a element displays a dotted border on FireFox and a shadow on Safari which looks a bit odd.

  3. Michael James Says:

    Thats some really interesting prototyping, hopefully people will look into this as a serious solution, i know dotnetnuke and others could do with it. Will we be seeing the yui working on this and then providing a standard?

  4. James Broad Says:

    Great stuff Chris! Very slick and i think you would get some happy screen readers/non JS adopters.

    I think to take this idea and make it much more sophsticated, it would be cool to play with being able to specify that certain elements on a page were editable (h1, li, a etc.). Almost venturing down a WYSIWYG route, just limiting to the content, though?

    Technical problems may hamper this idea, how would you be able to uniquely identify the information etc? You would have to rely on server side pre-processing to scan over the content, work out the elements to make editable and have a sensible way of writing out a respective form input field hook?

    note Christian: broken link “solution described here”…

  5. Isaac Z. Schlueter Says:

    Can’t you do it even more unobtrusively by building it to work entirely with CSS, and just ajaxing the form submission? Seems like an awful lot of script to do the hiding and showing of form elements when a :focus selector could do the heavy lifting. (Of course, IE might choke on that, I forget. If so, just add and remove a “focus” class, and rely on .focus instead of :focus. IE would then require JS to work, but oh well. Maybe a CSS hack could be employed to make non-JS IE just always show the inputs or something.)

    Here’s a first crack at it (tested only in Safari and Firefox so far.)
    http://foohack.com/tests/editable.php

    Also, the XHR could fire off on the onchange event instead of waiting for form submission, which would probably “feel faster” to the user, and be less actions. (Of course, it’d also be less forgiving of unintended changes.)

  6. Chris Says:

    @Isaac No I cannot, for the main reason I said in the post: it is just not accessible as screen readers work in different modes and nobody expects an input box in a heading. I added these as people would come up with CSS only solutions to counteract my evil JavaScript ways – as CSS is sooo much easier and doesn’t need hacks, ever*

    Assistive technology understands changes in the Dom – if you notify them, but they don’t get hover changes in CSS. When you talk accessibility you have to start with a logical HTML construct, and then you can work out how to style it. The example I’ve given does have issues, which were mentioned.

    I’ve sent the prototype to some friends of mine who use assistive technology and we can see what is going on.

    As to XHR firing onchange – it now fires onblur, which is factually the same :)

    * may contain irony

  7. Andreas Says:

    Cool! I’ve used the form-inside-semantic-elements approach myself for editing articles on my blog, but as editing requires login not everybody will suffer.

    I understand that “screen readers work in different modes and nobody expects an input box in a heading”, but what are the actual drawbacks of putting an input in a heading if we leave out SEO?

  8. Jeff Brown Says:

    cool I’m thinking of making a field that pops up a drop down instead of a text widget to limit the options, something like;

    [div]foo[/div]
    [select]
    [option]foo[/option]
    [option]bar[/option]
    [option]baz[/option]
    [option]quarfle[/option]
    [/select]

    That would really work for me!

Wait till I come! is the blog of Christian Heilmann , a developer evangelist living and working in London, England. Download vcard.

Feed me, Seymour: Entries (RSS) and Comments (RSS).