# `gno.land/p/moul/kit/ui/v0`
The shared display vocabulary for `r/moul` realms: the small set of rendering
decisions every realm was making on its own, made once.
First package of the `p/moul/kit/*` layer
([moul/gno-contracts#151](https://github.com/moul/gno-contracts/issues/151)).
`kit` composes the existing packages, it does not replace them.
## Why it exists
Measured across 118 realm directories in this repo:
| | |
|---|---|
| Realm dirs importing **zero** `p/moul/*` | 79 of 118 |
| Realm lines inside `Render` / `render*` | 5,909 of 23,276 (25.4%) |
| Lines in duplicated private helpers | 857 across 126 functions |
| Copies of `shortAddr` | 11, with **four different truncation rules** |
| Copies of `escapeInline` | 8, all a byte-identical seven-pair replacer |
The `shortAddr` number is the one that matters: the same account rendered
differently depending on which realm you opened. That is not duplication, it is
four answers to one question.
## What is here, and what is deliberately not
This package does **not** re-export markdown primitives. Headings, bold, lists,
code blocks and links already have an owner in
[`p/moul/md`](https://github.com/moul/gno-contracts/tree/main/p/moul/md); import that alongside. What lives here is only
what had no owner and was therefore copy-pasted.
```go
import (
"gno.land/p/moul/kit/ui/v0"
"gno.land/p/moul/md/v0"
)
func Render(path string) string {
t := ui.NewTable("#", "Player", "Score")
for i, p := range players {
t.Row(strconv.Itoa(i+1)+ui.Podium(i), ui.Addr(p.addr), ui.Cell(p.label))
}
return md.H1("Leaderboard") + t.OrEmpty("Nobody has played yet.")
}
```
| | |
|---|---|
| `Addr(a)` | `` `g1manfre…dlf5` ``, the one address format |
| `AddrFull(a)` | the full address, in backticks |
| `AddrText(a)` | shortened, no backticks, for a link title |
| `AddrOf(s)` | `Addr` for an address already in string form (an avl key) |
| `Short(s)`, `ShortN(s, head, tail)` | the same rule for any string: a URL, a handle, a commitment hash |
| `Inline(s)`, `Cell(s)` | escape user text, delegated to [`p/nt/markdown/sanitize`](/p/nt/markdown/sanitize/v0) |
| `Excerpt(s, width)` | a preview of user prose: cut to `width` runes, then escape. That order, because escaping first and cutting second strands a backslash |
| `Action(title, fn, args...)` | a clickable call, instead of prose telling the reader to type a function name |
| `ActionIn(pkgPath, title, fn, args...)` | the same, against another realm |
| `NewTable(headers...)`, `.Row(...)`, `.String()`, `.OrEmpty(msg)` | GFM tables |
| `Empty(msg)` | the italic placeholder where a list would be |
| `Podium(rank)` | 🥇🥈🥉, or `""` past third |
| `Join(sep, parts...)` | concatenate, skipping empty sections |
## The escaping contract
Table cells and `Action` titles are **markdown, not plain text**.
- Anything that came from a user goes through `Cell` (inside a table) or
`Inline` (anywhere else) before it reaches this package.
- Output of `Addr`, `AddrFull`, `AddrOf` and `Podium` is already safe and must
**not** be escaped again.
`Table` renders the GFM table itself rather than delegating to
[`p/moul/mdtable`](https://github.com/moul/gno-contracts/tree/main/p/moul/mdtable), which unconditionally rewrites `|` to
`|` in every cell. Stacked on `Cell`, which already emits the GFM escape
`\|`, that double-escapes into a stray backslash (`a\|b`, found while
porting `guestbook`). One escaping stage is the only way to get this right, and
it has to be the stage that knows whether the text is user input.
`Action` also escapes its title, which
[`p/moul/helplink`](https://github.com/moul/gno-contracts/tree/main/p/moul/helplink) does not (it carries an `// XXX:
escape title` where this would go).
## Design rule
**The safe, conventional thing must be the shortest thing to type.** A realm
author reaching for the obvious call has to land on the correct behaviour;
that is the only mechanism that stops these helpers from being rewritten a
twelfth time.
<!-- BEGIN GNOCONTRACTS FOOTER (generated by `make readmes`; do not edit below) -->
---
Part of **[moul/gno-contracts](https://github.com/moul/gno-contracts)** — moul's versioned gno.land contracts. See the repository for the full catalog, build/test tooling, and usage.
**Dependency graph:**

> ⚠️ **Disclaimer:** provided as-is, without warranty; not security-audited. Full disclaimer: [DISCLAIMER](https://github.com/moul/gno-contracts/blob/main/DISCLAIMER.md).
<!-- END GNOCONTRACTS FOOTER -->
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.