The XHTML label
is highly flexible, with the
theoretical ability to appear anywhere within the same form as its associated form control:
<form action="example" method="get"> <fieldset> <input type="text" name="somewhereelse" id="somewhereelse" size="26" value="My label is somewhere else …" /> <br /> <label for="before">It can be <strong>before</strong> the control.</label> <input type="text" name="before" id="before" /> <br /> <input type="checkbox" name="after" id="after" /> <label for="after">It can be <strong>after</strong> the control.</label> <br /> <label for="somewhereelse">It can be <strong>somewhere else</strong> in the form.</label> <br /> <label>It can be <em>even</em> be … <input type="text" name="around" id="around" /> … wrapped <strong>around</strong> the control!</label> </fieldset> </form>
Of course, theory tends to break down in practice. Screenreaders generally require the label to either enclose or be adjacent to the control, rather than wandering off on its own. In theory, wrapping a label
round the control should implicitly associate the label with the control (as in the example code above). But, in practice, many user agents screenreaders still require the for
attribute to recognise the association.
Still, some web designers have found wrapping controls in their label
elements the best starting point for styling a form. Unfortunately, Wicket's SimpleFormComponentLabel
cannot cope with that situation, since it replaces its entire body (including the control itself) with the label text defined in its model.
The solution is to use FormComponentLabel
for adding the correct id
to the label's for
attribute, but add the actual text of the label in with other components – typically a Label
bound to a span
. For example, in the form in ExamplePage.html:
<label for="something" wicket:id="somethingLabel"> <span wicket:id="somethingLabelSpan">[Label text]</span> <input type="text" name="something" id="something" wicket:id="something" /> </label>
And in ExampleForm.java:
/* Bind a TextField to the input element: */ TextField somethingField = new TextField("something"); somethingField.setOutputMarkupId(true); /* This could equally pull a label out of a resource. */ somethingField.setLabel(new Model("Something or other: ")); /* Bind a FormComponentLabel component to the label element: */ FormComponentLabel somethingLabel = new FormComponentLabel("somethingLabel",somethingField); /* Add the field to the containing label. * This will automatically update the "for" attribute to match: */ somethingLabel.add(somethingField); Label somethingLabelSpan = new Label("somethingLabelSpan",somethingField.getLabel()); /* Get rid of the span tag, leaving the label only: */ somethingLabelSpan.setRenderBodyOnly(true); /* Add the label span to the containing label: */ somethingLabel.add(somethingLabelSpan); /* Finally, add the containing label to the form: */ this.add(somethingLabel);