A DSL for UI Layouts

written by Neh Thalggu on 2025-11-29

I know this is probably more me than you, dear reader. But I just don't like working in two dimensions.

Laying out things like web-page designs or UI designs is a faff. If I use the mouse it's just OK. But a bit laborious.

On the other hand, declarative HTML-like and templating languages SHOULD be fine. But can become hugely complicated.

That's because

Now the separation of concerns which the HTML / CSS distinction is meant to represent is a fine thing. But in practice the two don't come apart so easily.

And in other ways of building forms, imperatively, in more traditional GUI libraries, we don't even have the virtues claimed for HTML. And again, the layout and the rest of what happens in the layout can get very intertwingled.

So I've been thinking for a while about a nice simple DSL that should represent just layout information. Just how a space should be carved into regions.

I played with an early prototype of this as an example in Neh-Thalggu

This week I've been exploring Canva apps from a developer perspective. I've been playing with putting some Patterning-derived apps there. But while doing so, I wondered whether my DSL would also work for making forms there.

And so I'm also playing with expanding this UI DSL a bit. To define, at first, paper forms.

The core idea is that all layouts are effectively blocks that are nested and arranged either horizontally or vertically. So why not use two different kinds of brackets, one for each?

In my DSL we use square brackets to represent vertical flow. So

[header body footer]

means header, body and footer flowed vertically.

Angle brackets represent horizontal flow. So

[header <col1 col2> footer]

turns the second section into two columns. And we can go on, nesting as much as we like.

[header 
   <maincolumn
     [sidebar1 sidebar2 sidebar3]>
 footer] 

Now it's important to note here that the language doesn't assign any meaning to the labels we give. These are really just symbols that mean whatever the user of the language wants them to mean. In the Canva app I'm working on, they just become text headers. While in a code-generator or Neh-Thalggu or embedded in a GUI framework, they might be references or tags that can be matched to specific GUI components.

Even with this simple language we can already say (and read) things clearly and concisely, that would otherwise be lost in the thickets of other functionality.

But we do need more control over relative sizes of the boxes. By default they are evenly divided. So if there are three things in a vertical flow, we assign a third of the space to each.

We can change this by adding a suffix to a label. This suffix represents (roughly) the ratio of the space this element should take up compared to its default. Let's suppose we think the header and the footer don't need to take up their full third of the screen. But only a proportion of that allotted space. We'd write something like this

[header(1/2) 
   <maincolumn
     [sidebar1 sidebar2 sidebar3]>
 footer(1/2)] 

This tells the layout engine to halve the space for both header and footer to the equivalent of 1/6 of the total vertical space each. Leaving 4/6 for the main section. In practice it doesn't work out exactly like this. Each specific request for space impacts the share that other sections get. But it's close enough that, with a small amount of fiddling, you can find reasonably nice proportions for each section.

If we want a section to claim more of the available space, we put a ratio that's greater than 1. In this example, the maincolumn demands 3 times its half of the width adding up to 3/4.

[header(1/2) 
 <maincolumn(3)
      [sidebar1 sidebar2 sidebar3]> 
 footer(1/3)]

Here's how the above gets rendered.

So. I think this is plausible. If I need to make simple SVG page templates, with labelled boxes I can. And I think hope this might well be a useful little tool in Canva. (Though with the caveat I'm not sure the average Canva user will particularly like working this way.)

The bigger test will come when I get back to the suite of music composition apps I'm currently working on, where I need to define a more complex GUI. I'm hoping I can use this to generate the layout code for that. But we'll see.

In the meantime, you can play with it here

And at some point the revised, improved version of this language will find its way back to Neh Thalggu as an example DSL there.