Skip to content

Writing HTML inside V

Ned Palacios edited this page May 1, 2020 · 1 revision

The limitation of the V language and the prominence of front-end frameworks on the Web gave rise to the declarative way of creating user interfaces. With the html submodule, you can build a discrete user interface and generate HTML inside V!

The Tag

The html.Tag struct is the important part of the html submodule. It has the following properties that allows us to define the HTML tag we want to use.

// Simple tag
img_tag := html.Tag{name: 'h1', props: {'src': 'bird.jpg'}}

// Tag with children
p_tag := html.Tag{name: 'p', children: [
    html.Tag{name: 'text', text: 'This is a '},
    html.Tag{name: 'b', text: 'bold text.'}
]}

It is important to explicitly state the fields when creating a new tag since there are some struct fields such as children, props, and text that are optional to use.

Rendering

Vex has a dedicated Resp response function named send_html which converts the passed array of tags into an HTML representation and sets the content type to text/html.

content := [html.Tag{name: 'text', text: 'Hello!'}]
res.send_html(layout(content), 200)
// <h1>Hello!</h1>

Components

There are some parts that can be reused for other pages or you want to be able to generate the markup based on the data provided and it is possible by creating a function that returns the html.Tag. In this example, we created a layout and h1 components.

fn layout(body []html.Tag) html.Tag {
    template := html.Tag{name: 'html', children: [
        html.Tag{name: 'head', children: [
            html.Tag{name: 'meta', props: { 'http-equiv': 'Content-Type', 'content': 'text/html;charset=UTF-8' }},
            html.Tag{name: 'meta', props: { 'name': 'referrer', 'content': 'origin-when-cross-origin'}},
            html.Tag{name: 'title', text: 'Vex SQLite Test'}
        ]},
        html.Tag{name: 'body', children: body}
    ]}

    return template
}

fn h1(props map[string]string, children []html.Tag) html.Tag {
    return html.Tag{name: 'h1', props: props, children: children}
}

fn main() {
    mut s := server.new()
    s.get('/test', fn (req ctx.Req, res mut ctx.Resp) {
        text := h1({}, [html.Tag{name: 'text', text: 'hello'}])
        content := [text]

        res.send_html(layout(content), 200)
    })
    s.serve(8000)
}

text Tag vs text field

Deciding whether to use the text tag or the text field can be confusing. Here are some pointers for you to instill to your mind:

  • The text tag must be used in conjunction with the text field.
  • The text field can be used if you don't want to nest the text tag which can be a hassle and just directly use a simple text as the children of the tag.
  • Nesting the text tag is recommended if you have incorporated other formatting elements such as the b(bold) and i(italic) tags.
  • The text field is recommended for style and script tags.
Clone this wiki locally