| description | The Text object is a mini-language for representing rich text formatting commonly used in the fediverse. Learn how to format your text using the Text object. |
|---|
The Text object is a mini-language for representing rich text formatting
commonly used in the fediverse. For example, you can emphasize
some part of the text, or include a mention to another fediverse
account.
The Text object consists of two types of elements: blocks and inlines.
Type-wise they are represented by the Text<"block"> and Text<"inline">.1
Blocks are usually used for paragraphs, and inlines are used for
formatting constructs like emphases or links.
The distinction between blocks and inlines is important because some formatting
constructs are only allowed in blocks or inlines. For example, you cannot
include a paragraph inside an emphasis construct. Since the concept of blocks
and inlines corresponds to the same concept in the HTML, you can think of them
as the <div> and <span> elements in the HTML, respectively.
The parameters that take the Text object, such as Session.publish() method
or createBot() function's summary
parameter, are usually of the type
Text<"block">. The simplest way to create a Text<"block"> object is to
use the text() template string tag, which we will discuss in the right next
section.
First of all, BotKit provides a template string tag text() to format your
text. Here's how you can use it:
import { text } from "@fedify/botkit";
const yourText = text`Your text goes here!`; // [!code highlight]For example, if you want to publish a message with the text
Hello, world!
to the fediverse, you can write:
// @noErrors: 2307
import type { Bot } from "@fedify/botkit";
const bot = {} as unknown as Bot<void>;
// ---cut-before---
import { strong, text } from "@fedify/botkit";
import { bot } from "./bot.ts"; // A hypothetical bot object
const session = bot.getSession("https://mydomain");
await session.publish(
text`Hello, ${strong("world")}!` // [!code highlight]
);As you can see in the example above, you can compose other Text objects
together using the template string tag. In this document, we will discuss
various formatting constructs that you can use in the Text object.
You can put any JavaScript object inside the ${} interpolation.
Those objects will be expanded or converted to a string according to their
types:
If you put another Text object inside the interpolation, it will be
concatenated to the parent Text object. For example:
import { text, em } from "@fedify/botkit";
// ---cut-before---
text`Hello, ${em("world")}.`The above code will create a text like this:
Hello, world.
There are other formatting constructs that you can use in the Text object.
See the below sections for more information.
Note
Although you can put a block object, it will close the current paragraph and start a new block. For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`Hello! ${text`This is a new paragraph.`}`The above code will create two paragraphs like this:
Hello!
This is a new paragraph.
If you put a block object at the boundary of the block, it will work as expected. For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`Hello!\n\n${text`This is a new paragraph.`}\n\nThis is the last paragraph.`The above code will create three paragraphs like this:
Hello!
This is a new paragraph.
This is the last paragraph.
If you put an Actor object (provided by Fedify) inside the interpolation,
it will be rendered as a mention. For example:
import { type Message, type MessageClass, text } from "@fedify/botkit";
const message = {} as unknown as Message<MessageClass, void>;
// ---cut-before---
text`Hello, ${message.actor}.`The above code will create a text like this:
Hello, @fedify@hollo.social.
This API is available since BotKit 0.2.0.
If you put an Emoji object (provided by Fedify) inside the interpolation,
it will be rendered as a custom emoji. You usually get Emoji objects from
the Reaction.emoji property. For example:
import { type Reaction, text } from "@fedify/botkit";
const reaction = {} as unknown as Reaction<void>;
// ---cut-before---
text`Here's a custom emoji: ${reaction.emoji}.`If you put a URL object inside the interpolation, it will be rendered as a
link. For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`Here's a link: ${new URL("https://botkit.fedify.dev/")}.`The above code will create a text like this:
Here's a link: https://botkit.fedify.dev/.
If you put any other JavaScript object inside the interpolation, it will be
converted to a string—it's the same as calling String() on the object.
For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`The number is ${42}.`The above code will create a text like this:
The number is 42.
If an interpolated string has line breaks, they will be preserved in the text. For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`Here's a multiline text:
${"First line.\nSecond line."}`The above code will create a text like this:
Here's a multiline text:
First line.
Second line.
Note
Even if you put an HTML string inside the interpolation, it will be escaped automatically:
import { text } from "@fedify/botkit";
// ---cut-before---
text`The following HTML will be escaped: ${"<strong>bold</strong>"}.`The above code will create a text like this:
The following HTML will be escaped: <strong>bold</strong>.
Only way to format the text is to use the formatting constructs described in the following sections.
The text() template string tag creates a block Text object.
You can create a paragraph by simply writing a text. If you want to create multiple paragraphs, you can split them with two or more consecutive line breaks. For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`This is the first paragraph.
This is the second paragraph.\n\nThis is the last paragraph.`The above code will create three paragraphs like this:
This is the first paragraph.
This is the second paragraph.
This is the last paragraph.
Paragraphs are separated by the <p> HTML element.
If you want to insert a hard line break, put a single line break (\n)
between the lines. For example:
import { text } from "@fedify/botkit";
// ---cut-before---
text`This is the first line of the first paragraph.
This is the second line of the first paragraph.
This is the second paragraph.`The above code will create two paragraphs like this:
This is the first line of the first paragraph.
This is the second line of the first paragraph.This is the second paragraph.
It corresponds to the <br> HTML element.
BotKit provides two kinds of emphasis: strong() emphasizes which is usually
rendered as bold, and em() emphasizes which is usually rendered as
italic. Both are inlines, so you can put them inside the interpolation.
For example:
import { em, strong, text } from "@fedify/botkit";
// ---cut-before---
text`You can emphasize ${strong("this")} or ${em("this")}!`The above code will create a text like this:
You can emphasize this or this!
You can nest the emphasis constructs:
import { em, strong, text } from "@fedify/botkit";
// ---cut-before---
text`You can emphasize ${strong(em("this"))}!`The above code will create a text like this:
You can emphasize this!
You can make a link to a URL by using the link() function. It returns
an inline Text object that represents a link. For example:
import { link, text } from "@fedify/botkit";
// ---cut-before---
text`Here's a link: ${link("https://fedify.dev/")}.`The above code will create a text like this:
Here's a link: https://fedify.dev/.
You can customize the label of the link if you provide two arguments:
import { link, text } from "@fedify/botkit";
// ---cut-before---
text`Here's a link: ${link("Fedify", "https://fedify.dev/")}.`The above code will create a text like this:
Here's a link: Fedify.
The label can have other formatting constructs:
import { em, link, text } from "@fedify/botkit";
// ---cut-before---
text`Here's a link: ${link(em("Fedify"), "https://fedify.dev/")}.`The above code will create a text like this:
Here's a link: Fedify.
You can mention another fediverse account by using the mention() function.
It returns an inline Text object that represents a mention. For example:
import { mention, text } from "@fedify/botkit";
// ---cut-before---
text`Hello, ${mention("@fedify@hollo.social")}!`The above code will create a text like this:
Hello, @fedify@hollo.social!
Or you can mention an account by its actor URI:
import { mention, text } from "@fedify/botkit";
// ---cut-before---
text`Hello, ${mention(new URL("https://hollo.social/@fedify"))}!`The result is equivalent to the previous example:
Hello, @fedify@hollo.social!
You can customize the label of the mention:
import { mention, text } from "@fedify/botkit";
// ---cut-before---
text`Hello, ${mention("Fedify", new URL("https://hollo.social/@fedify"))}!`The above code will create a text like this:
Hello, Fedify!
Note
The mention() construct does not only format the text but also notifies
the mentioned account. The mentioned account will receive a notification
about the mention. If you want to just link to the account without
notifying, use the link() construct instead.
You can include a hashtag in the text using the hashtag() function.
It is an inline construct. For example:
import { hashtag, text } from "@fedify/botkit";
// ---cut-before---
text`Here's a hashtag: ${hashtag("#BotKit")}.`The above code will create a text like this:
Here's a hashtag: #BotKit.
It does not matter if you put the leading "#" or not. The hashtag()
function will add the leading "#" if it is not present. For example:
import { hashtag, text } from "@fedify/botkit";
// ---cut-before---
text`Here's a hashtag: ${hashtag("BotKit")}.`The result is equivalent to the previous example:
Here's a hashtag: #BotKit.
Note
The hashtag() function does not only format the hashtag but also denotes
the hashtag so that ActivityPub software can recognize it as a hashtag.
The hashtag will be searchable in the fediverse (some software may search it
only from public messages though). If you want to just link to the hashtag
without denoting it, use the link() construct instead.
You can include a code in the text using the code() function,
which is usually rendered as monospaced font. It is an inline construct.
For example:
import { code, text } from "@fedify/botkit/text";
// ---cut-before---
text`Here's a code: ${code("console.log('Hello, world!')")}.`The above code will create a text like this:
Here's a code:
console.log('Hello, world!').
Caution
It is not a code block, but an inline code.
This API is available since BotKit 0.2.0.
You can include a custom emoji in the text using the customEmoji() function.
It is an inline construct.
In order to use the customEmoji() function, you need to define custom emojis
first. You can define custom emojis by using the Bot.addCustomEmojis()
method after creating the bot:
import type { Bot } from "@fedify/botkit";
const bot = {} as unknown as Bot<void>;
// ---cut-before---
// Define custom emojis:
const emojis = bot.addCustomEmojis({
// Use a local image file:
botkit: { file: `${import.meta.dirname}/botkit.png`, type: "image/png" },
// Use a remote image URL:
fedify: { url: "https://fedify.dev/logo.png", type: "image/png" },
});The ~Bot.addCustomEmojis() method returns an object that contains the custom
emojis. You can use the keys of the object to refer to the custom emojis.
For example:
import { customEmoji, text } from "@fedify/botkit/text";
import type { DeferredCustomEmoji } from "@fedify/botkit/emoji";
const emojis = {} as Readonly<Record<"botkit" | "fedify", DeferredCustomEmoji<void>>>;
// ---cut-before---
text`Here's a custom emoji:
${customEmoji(emojis.botkit)} by ${customEmoji(emojis.fedify)}.`Note
The markdown() function does not support raw HTML syntax.
Sometimes you have a Markdown text and want to render it as a Text object.
You can use the markdown() function to convert the Markdown text to the Text
object. It is a block construct. For example:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`
Here's a Markdown text.
- I can have a list.
- I can have a **bold** text.
- I can have an _italic_ text.
`)The above code will create a text like this:
Here's a Markdown text.
- I can have a list.
- I can have a bold text.
- I can have an italic text.
You can also put the markdown() function inside the interpolation:
import { markdown, text } from "@fedify/botkit/text";
// ---cut-before---
text`The following is a Markdown text:
${markdown(`
Here's a Markdown text.
- I can have a list.
- I can have a **bold** text.
- I can have an _italic_ text.
`)}
`The above code will create a text like this:
The following is a Markdown text:
Here's a Markdown text.
- I can have a list.
- I can have a bold text.
- I can have an italic text.
Besides the standard Markdown syntax, the markdown() function also supports
mentioning and hashtag syntax for the fediverse.
The following example shows how to mention an account:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`Hello, @fedify@hollo.social!`)The above code will create a text like this:
Hello, @fedify@hollo.social!
Note
The markdown() function does not only format the mention but also notifies
the mentioned account. The mentioned account will receive a notification
about the mention. If you want to just link to the account without
notifying, use the normal link syntax instead:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`Hello, [@fedify@hollo.social](https://hollo.social/@fedify)!`)If you want @-syntax to be treated as a normal text, turn off the syntax
by setting the mentions option to false:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`Hello, @fedify@hollo.social!`, { mentions: false })The above code will create a text like this:
Hello, @fedify@hollo.social!
The following example shows how to include a hashtag:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`Here's a hashtag: #BotKit`)The above code will create a text like this:
Here's a hashtag: #BotKit.
Note
The markdown() function does not only format the hashtag but also denotes
the hashtag so that ActivityPub software can recognize it as a hashtag.
The hashtag will be searchable in the fediverse (some software may search it
only from public messages though). If you want to just link to the hashtag
without denoting it, use the normal link syntax instead:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`Here's a hashtag: [#BotKit](https://mastodon.social/tags/botkit)`)If you want #-syntax to be treated as a normal text, turn off the syntax
by setting the hashtags option to false:
import { markdown } from "@fedify/botkit/text";
// ---cut-before---
markdown(`Here's a hashtag: #BotKit`, { hashtags: false })The above code will create a text like this:
Here's a hashtag: #BotKit.
You can determine if the text mentions an account by using the mentions()
function. It returns true if the text mentions the account,
otherwise false:
import type { Session } from "@fedify/botkit";
/** A hypothetical function that returns an Actor object. **/
declare function getActor(handle: string): Actor;
const session = {} as unknown as Session<unknown>;
// ---cut-before---
import type { Actor } from "@fedify/botkit";
import { markdown, mention, mentions, text } from "@fedify/botkit/text";
const actor: Actor = getActor( // A hypothetical function that returns an Actor object
"@fedify@hollo.social"
);
const actor2: Actor = getActor("@another@example.com");
const md = markdown("Hello, @fedify@hollo.social!");
console.log(await mentions(session, md, actor)); // true
console.log(await mentions(session, md, actor2)); // false
const txt = text`Hi, ${actor2}!`
console.log(await mentions(session, txt, actor)); // false
console.log(await mentions(session, txt, actor2)); // true
const noMention = text`Hello, world!`;
console.log(await mentions(session, noMention, actor)); // false
console.log(await mentions(session, noMention, actor2)); // falseFootnotes
-
More precisely, the
Texttype has two type parameters: the first one is the type of the element:"block"or"inline", and the second one isTContextData, the Fedify context data. ↩