Skip to content


Pages in WebDSL can be defined using the following construct:

 page [pagename]( [page-arguments]* ){ [page-elements]* }

There are basic output elements for structure and layout of the page, such as title and header.


page root {
  title { "Page title" }
  section {
    header{ "Hello world." }  
    "Greetings to you."

Page Parameters

Pages can have parameters, and output is used for inserting data values.


page user(u : User) {
  "The name of this user is " output(

Input Forms

The form element in combination with submit is used for submitting data. input elements perform automatic data binding upon submit. For more information about forms, go to the Forms page.


page editUser(u:User){
    submit action{} { "save" } 


Pages can be made reusable by declaring them as template, and calling them from other pages or templates.


template common(){
  header{ "my page" }
page root(){


The output(<expression>) template call is used to display a value in a page. It can also be used with Entity type expressions, and collections.


page user(u:User){

The output template can be customized for each entity type.


template output(u:User){
  "user with name: " output(
navigate <page call> { <page element*> }

Link to a page. For example:

page news() { "News" }


Declares the title of the current page.

title { element* }


Declares the description of a page (not visible, added as description meta tag in the head section of a page). This data is often viewed in search result snippets. Introduced in WebDSL 1.3.0.

description { element* }


section { element* }

Indicate sections in a document; may be nested. May include a

header { element* }

element that indicates the section title.


image ( <string with relative or absolute path to image> )

Displays an image. Images placed in an "images" folder in the root directory of your application will be automatically copied during deployment.


page root(){


Lists can be created with the list and listitem elements.


list {
  listitem { "Milk" }
  listitem { "Potatoes" }
  listitem { "Cheese (lots)" }


Tables can be created with the table, row, and column elements.


table  {
  row { column{ "Username" } column{ output( } }
  row { column{ "Password" } column{ "it's a secret" } }


block{ <page element*> }
block(String){ <page element*> }

Groups text; optionally defines a class for referencing in CSS. Results in a <div> element in HTML.


Templates enable reuse of page elements. For example, a template for a footer could be:

template footer() { All your page are belong to us. }

This template can be included in a page with a template call:

page example(){

Like pages, templates can be parameterized.

template edit(g:Group){
  form {
    submit action {} { "save" }

page editGroup(g:Group){


While pages must have unique names, templates can be overloaded. The overloading is resolved compile-time, based on the static types of the arguments.

template edit(g:Group){...}
template edit(u:User){...}

page editGroup(g:Group){

Dynamically scoped templates redefinitions

Template definitions can be redefined locally in a page or template, to change their meaning in that specific context. All uses are replaced in templates called from the redefining template.

template main{
template body(){
  "default body"
page root(){
  template body(){
    "custom body"


Iterating a collection of entities or primitives can be done using a for loop. There are three types of for loops for templates:


    for(id:t in e){ elem* }

This type of for loop iterates the collection produced by expression e, which must contain elements of type t. The elements in the collection are accessible through identifier id.

The collection can be filtered:

    for(id:t in e filter){ elem* }


This for loop iterates all the entities in the database of type t. These can also be filtered. Note that it is more efficient to retrieve the objects using a filtering query and use the regular for loop above for iteration.

    for(id:t){ elem* }
    for(id:t filter){ elem* }

For Count

This for loop iterates the numbers from e1 to e2-1.

    for(id:Int from e1 to e2){ elem* }

For Separator

All three template for loops can be followed by a separated-by declaration, which will separate the outputs from the for loop with the declared elem*.

    separated-by{ elem* }

For-loop Filter

The filter part of a for loop can consist of four parts:


    where e1

e1 is a boolean expression which needs to evaluate to true for the element to be iterated.

Order By

    order by e2 asc/desc

e2 is an expression that needs to produce a primitive type such as String or Int, which will be used to order the elements ascending or descending.


    limit e3

e3 is an Int expression which will limit the number of elements that get iterated.


    offset e4

e4 is an Int expression which will offset the starting element of the iteration.

Each of the four parts is optional, but they have to be specified in this order. The filtering is done in the application, so use queries instead of filters to optimize the WebDSL application.

XML Embedding

XML fragments can be embedded directly in templates. This allows easy reuse of existing XHTML fragments and CSS. For example:

template main() {
  <div id="pagewrapper">
    <div id="header">
    <div id="footer">
      <p />"powered by " <a href="">"WebDSL"</a><p />
  <some:tag />

While the name and attribute names are fixed, the attribute values can be any WebDSL expression that produces a string:

template test(i : Int) {
  <div id="page" + "wrapper" + i />

Include CSS

The includeCSS(String) template call allows you to include a CSS file in the resulting page. CSS files can be included in your project by placing them in a stylesheets/ directory in the project root.

Example 1:

page root() {

It is also possible to include a CSS file using an absolute URL.

Example 2:

page root() {

The media attribute can be set by passing it as second argument in includeCSS(String,String)

Example 3:

page root(){

Include Javascipt

The includeJS(String) template call allows you to include a javascript file in the resulting page. Javascript files can be included in your project by placing them in a javascript/ directory in the project root.

Example 1:

page root() {

It is also possible to include a Javascript file using an absolute URL.

Example 2:

page root() {

Page Not Found Error

When an invalid URL is being requested from a WebDSL application, the default response is to give a 404 error. To customize this error page, define a pagenotfound page in your application.


page pagenotfound() {
  title{ "myapp / page not found (404)" }
  template body() {
    par{ "That page does not exist!" }
    par{ "Maybe you can find what you are looking for using the search page." }

Raw output

By default, any template content will be escaped, if you want to include a string directly in the page source use rawoutput.



HTML Element Attributes on Template Call

Setting HTML element attributes is supported for calls to built-in templates, the syntax is as follows:

templatename(...)[attrname=e, ...]{ ... }

attrname is an attribute name, and e is a webdsl expression such as "foo" or "foo"+bar.


page root(){ 
  var somevalue := "lo"
  image("/images/logosmall.png")[alt = somevalue+"go", longdesc = "blablabla"]
  navigate root()[title = "root page"]{ "root" }

Override Modifier

Template and page definitions can be overridden using the override modifier, e.g. to override a built-in page such as pagenotfound:

override page pagenotfound(){
  "page does not exist!"

SQL Logging for Page Rendering

add ?logsql after the URL of a page to get a log of all the SQL queries executed to render that page

for applications with access control enabled, accessing this log is disabled by default, it can be enabled using an access control rule:

rule logsql { check }


rule logsql { principal.isAdmin }
Back to top