TamboUI provides a BBCode-style markup parser for creating styled Text objects from strings.
This is a convenient alternative to building Line and Span objects manually.
Basic Usage
// Parse markup into styled Text
Text text = MarkupParser.parse("This is [bold]bold[/bold] and [red]red[/red].");
// Use with widgets
Paragraph paragraph = Paragraph.from(
MarkupParser.parse("[cyan]Status:[/cyan] [bold green]Ready[/]")
);
Syntax Reference
Style Tags
Style tags use square brackets with a tag name:
[tagname]content[/tagname]
Modifier Tags
| Tag | Effect | Aliases |
|---|---|---|
|
Bold text |
|
|
Italic text |
|
|
Underlined text |
|
|
Dimmed/faint text |
|
|
Swap foreground and background |
|
|
Strikethrough text |
|
Colors
Colors can be specified the ways ColorConverter supports:
-
Named colors:
red,green,blue,yellow,cyan,magenta,white,black,gray, etc. -
Hex colors:
#RGB,#RRGGBB -
RGB colors:
rgb(r,g,b) -
Indexed colors:
indexed(index)
Only named colors are treated as tags/classes; explicit colors are not possible to be styled.
Implicit Close
Close the most recent tag without naming it:
[bold]Hello[/] World
This is equivalent to:
[bold]Hello[/bold] World
Implicit close is useful for deeply nested tags:
[red][bold]Important[/][/] vs [red][bold]Important[/bold][/red]
Compound Styles
Combine multiple styles in a single tag by separating them with spaces:
[bold red]Error message[/]
[italic cyan]Hint text[/]
[bold underlined yellow]Warning![/]
All tokens in a compound style become CSS classes for targeting (see CSS Class Targeting).
Background Colors
Use on to specify a background color:
[white on blue]Highlighted text[/]
[black on yellow]Warning banner[/]
[bold red on white]Alert![/]
Hyperlinks
Create clickable links (in supported terminals):
[link=https://example.com]Click here[/link]
Escaped Brackets
Two escape mechanisms are supported for literal brackets:
Double Brackets
Use [[tag]] for markup renders as: Use [tag] for markup
Content with ]] closing renders as: Content with ] closing
Backslash Escapes
Use \[tag] for literal renders as: Use [tag] for literal
Content with \] closing renders as: Content with ] closing
Path: C:\\Users\\name renders as: Path: C:\Users\name
Supported backslash escapes: \[, \], \\. Other sequences (like \n) are preserved as-is.
Nesting
Tags can be nested for combined effects:
[red]This is red and [bold]this is red and bold[/bold][/red]
Custom Style Resolver
A StyleResolver lets you define custom tags that map to styles:
MarkupParser.StyleResolver resolver = tagName -> {
switch (tagName) {
case "keyword": return Style.EMPTY.fg(Color.CYAN).bold();
case "string": return Style.EMPTY.fg(Color.GREEN);
case "comment": return Style.EMPTY.fg(Color.GRAY).italic();
case "error": return Style.EMPTY.fg(Color.WHITE).bg(Color.RED).bold();
default: return null;
}
};
Text code = MarkupParser.parse(
"[keyword]public[/] [keyword]void[/] main([string]\"Hello\"[/]) [comment]// entry point[/]",
resolver
);
Resolver Priority
The resolver has priority over built-in styles. This means you can redefine what built-in color names mean:
// Redefine "red" to mean something else in your theme
MarkupParser.StyleResolver themeResolver = tagName -> {
if ("red".equals(tagName)) {
return Style.EMPTY.fg(Color.hex("#ff6b6b")); // Custom red
}
return null;
};
// Now [red] uses your custom color instead of Color.RED
Text text = MarkupParser.parse("[red]Custom red[/]", themeResolver);
Merging Resolver and Compound Styles
When using compound styles with a resolver, both are merged. Inline styles (from the compound) override the resolver’s base style, similar to how CSS inline styles override class styles:
MarkupParser.StyleResolver resolver = tagName -> {
if ("error".equals(tagName)) {
return Style.EMPTY.fg(Color.CYAN).bold();
}
return null;
};
// [error] alone: cyan foreground + bold (from resolver)
Text t1 = MarkupParser.parse("[error]Message[/]", resolver);
// [error on red]: cyan foreground + bold + red background
// The resolver provides the base, compound adds the background
Text t2 = MarkupParser.parse("[error on red]Message[/]", resolver);
// [error yellow]: yellow foreground + bold
// Compound's yellow overrides resolver's cyan, but bold is kept
Text t3 = MarkupParser.parse("[error yellow]Message[/]", resolver);
// [error italic]: cyan foreground + bold + italic
// Compound adds italic to resolver's style
Text t4 = MarkupParser.parse("[error italic]Message[/]", resolver);
CSS Class Targeting
All tokens in a tag become CSS classes that can be targeted with stylesheets.
For compound styles, every token (except on) becomes a CSS class:
Text text = MarkupParser.parse("[error]message[/]");
// The span has Tags extension containing "error"
Text compound = MarkupParser.parse("[bold underlined yellow]Warning![/]");
// The span has Tags extension containing "bold", "underlined", "yellow"
Text background = MarkupParser.parse("[white on blue]text[/]");
// The span has Tags extension containing "white", "blue" (not "on")
This allows external CSS to target any style token:
/* Target all bold text */
.bold {
text-style: bold;
}
/* Target all yellow text */
.yellow {
color: #ffcc00;
}
/* Target error messages */
.error {
color: red;
text-style: bold;
}
Unknown Tags
Tags that aren’t recognized as built-in styles and aren’t resolved by a custom resolver are still tracked for CSS class targeting, but have no visual effect:
// "custom" is unknown, but tracked as a CSS class
Text text = MarkupParser.parse("[custom]styled by CSS[/custom]");
// Can be styled via CSS:
// .custom { color: magenta; }
Multi-line Text
Markup can span multiple lines:
Text multiline = MarkupParser.parse("""
[bold]Header[/]
[dim]This is a paragraph with [cyan]highlighted[/] text.[/]
[italic]Footer note[/]
""");
Examples
Status Messages
MarkupParser.parse("[green]SUCCESS[/] Operation completed");
MarkupParser.parse("[yellow]WARNING[/] Disk space low");
MarkupParser.parse("[bold red]ERROR[/] Connection failed");
Syntax Highlighting
MarkupParser.StyleResolver syntax = tag -> switch (tag) {
case "kw" -> Style.EMPTY.fg(Color.MAGENTA).bold();
case "str" -> Style.EMPTY.fg(Color.GREEN);
case "num" -> Style.EMPTY.fg(Color.CYAN);
case "cmt" -> Style.EMPTY.fg(Color.GRAY).italic();
default -> null;
};
Text code = MarkupParser.parse(
"[kw]int[/] x = [num]42[/]; [cmt]// answer[/]",
syntax
);
Rich Notifications
MarkupParser.parse("""
[bold white on blue] NOTICE [/]
Your session will expire in [bold yellow]5 minutes[/].
Please [link=https://example.com/save]save your work[/link].
""");
Summary Table
| Syntax | Description | Example |
|---|---|---|
|
Explicit close |
|
|
Implicit close (most recent) |
|
|
Compound styles |
|
|
Background color |
|
|
Hyperlink |
|
|
Double bracket escapes |
|
|
Backslash escapes |
|
Next Steps
-
Core Concepts - understand Text, Line, and Span
-
CSS Styling - external stylesheets for markup classes
-
Widgets Reference - using Text with widgets