> Docs > Html Builder > Code Organization
Each html document should be a subclass of Html4Doc
or Html5Doc
. In simple cases (e.g. throwaway code) you may use anonymous class
Html5Doc doc = new Html5Doc() // anonymous class {{ // instance initializer _head( _link().type("text/css").href("/site.css") ); _body(()-> { _p("hello, ", name); }); }};
However, it's generally better to declare an explicit class for the document. Parameters can be passed to the constructor. The document should be built complete upon constructor exit.
public class HelloHtml extends Html5Doc { public HelloHtml(String name) { _head( _link().type("text/css").href("/site.css") ); _body(()-> { _p("hello, ", name); }); } } // HttpHandler return new HelloHtml("world").toResponse(200);
App can establish a hierarchy of html templates. A template class creates a document with some blank areas, to be filled by subclasses. A template class can also define some convenience methods for subclasses to use.
public class TemplateHtml extends Html5Doc { protected DIV mainArea; public TemplateHtml(String title) { _head( _title(title), _link().type("text/css").href("/site.css") ); _body(()-> { _h1(title); mainArea = _div().id("main"); // to be filled by subclass constructor }); } // convenience methods. public A _url(String url) // don't overload super methods like _a(), _link() { return _a(url).href(url); } public void addCss(String cssFile) { head.add( _link().type("text/css").href(cssFile) ); } } public class ByeHtml extends TemplateHtml { public ByeHtml(String name) { super("good bye "+name); mainArea.add( _p("nice to meet you, ", name), _p("see you at ", _url("http://example.com")) ); addCss("/bye.css"); } }
Do not design a template class as an abstract class with abstract methods - it's not safe to invoke abstract methods in constructors.
When building a complex html, nesting can become too deep and unmanageable, for example,
_body(()->{ _div( _form(()->{ _p().add( _span( _a( ...
You can reorganize it into sub-routines, keep each one at reasonable length.
public QueryHtml() { _body(() -> { _div().id("d1").add(this::prologue); _div().add( _queryForm().id("form"), _p("fine prints") ); footer(); }); } void prologue() // code block { _p().id("p1").add("Lorem ipsum dolor sit amet"); _p().id("p2").add("Ut enim ad minim veniam"); } void footer() { _hr(); _p("Duis aute irure dolor in reprehenderit"); } FORM _queryForm() // custom builder method { return _form().action("/query").add( _input().name("q"), _mySelect("category", "apple", "orange"), _input().type("submit") ); } SELECT _mySelect(String name, String... options) // don't overload super's _select() method { SELECT select = _select().name(name); for(String opt : options) select.add( _option(opt) ); return select; }