mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			479 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
# Message formatting
 | 
						|
 | 
						|
Zulip supports an extended version of Markdown for messages, as well as
 | 
						|
some HTML level special behavior. The Zulip help center article on [message
 | 
						|
formatting](/help/format-your-message-using-markdown) is the primary
 | 
						|
documentation for Zulip's markup features. This article is currently a
 | 
						|
changelog for updates to these features.
 | 
						|
 | 
						|
The [render a message](/api/render-message) endpoint can be used to get
 | 
						|
the current HTML version of any Markdown syntax for message content.
 | 
						|
 | 
						|
## Code blocks
 | 
						|
 | 
						|
**Changes**: As of Zulip 4.0 (feature level 33), [code blocks][help-code]
 | 
						|
can have a `data-code-language` attribute attached to the outer HTML
 | 
						|
`div` element, which records the programming language that was selected
 | 
						|
for syntax highlighting. This field is used in the
 | 
						|
[playgrounds][help-playgrounds] feature for code blocks.
 | 
						|
 | 
						|
## Global times
 | 
						|
 | 
						|
**Changes**: In Zulip 3.0 (feature level 8), added [global time
 | 
						|
mentions][help-global-time] to supported Markdown message formatting
 | 
						|
features.
 | 
						|
 | 
						|
## Links to channels, topics, and messages
 | 
						|
 | 
						|
Zulip's markup supports special readable Markdown syntax for [linking
 | 
						|
to channels, topics, and messages](/help/link-to-a-message-or-conversation).
 | 
						|
 | 
						|
Sample HTML formats are as follows:
 | 
						|
``` html
 | 
						|
<!-- Syntax: #**announce** -->
 | 
						|
<a class="stream" data-stream-id="9"
 | 
						|
  href="/#narrow/channel/9-announce">
 | 
						|
 #announce
 | 
						|
</a>
 | 
						|
 | 
						|
<!-- Syntax: #**announce>Zulip updates** -->
 | 
						|
<a class="stream-topic" data-stream-id="9"
 | 
						|
  href="/#narrow/channel/9-announce/topic/Zulip.20updates/with/214">
 | 
						|
 #announce > Zulip updates
 | 
						|
</a>
 | 
						|
 | 
						|
<!-- Syntax: #**announce>Zulip updates**
 | 
						|
     Generated only if topic had no messages or the link was rendered
 | 
						|
     before Zulip 10.0 (feature level 347) -->
 | 
						|
<a class="stream-topic" data-stream-id="9"
 | 
						|
  href="/#narrow/channel/9-announce/topic/Zulip.20updates">
 | 
						|
 #announce > Zulip updates
 | 
						|
</a>
 | 
						|
 | 
						|
<!-- Syntax: #**announce>Zulip updates@214** -->
 | 
						|
<a class="message-link"
 | 
						|
  href="/#narrow/channel/9-announce/topic/Zulip.20updates/near/214">
 | 
						|
 #announce > Zulip updates @ 💬
 | 
						|
</a>
 | 
						|
```
 | 
						|
 | 
						|
The `near` and `with` operators are documented in more detail in the
 | 
						|
[search and URL documentation](/api/construct-narrow). When rendering
 | 
						|
topic links with the `with` operator, the code doing the rendering may
 | 
						|
pick the ID arbitrarily among messages accessible to the client and/or
 | 
						|
acting user at the time of rendering. Currently, the server chooses
 | 
						|
the message ID to use for `with` operators as the latest message ID in
 | 
						|
the topic accessible to the user who wrote the message.
 | 
						|
 | 
						|
The older stream/topic link elements include a `data-stream-id`, which
 | 
						|
historically was used in order to display the current channel name if
 | 
						|
the channel had been renamed. That field is **deprecated**, because
 | 
						|
displaying an updated value for the most common forms of this syntax
 | 
						|
requires parsing the URL to get the topic to use anyway.
 | 
						|
 | 
						|
When a topic is an empty string, it is replaced with
 | 
						|
`realm_empty_topic_display_name` found in the [`POST /register`](/api/register-queue)
 | 
						|
response and wrapped with the `<em>` tag.
 | 
						|
 | 
						|
Sample HTML formats with `"realm_empty_topic_display_name": "general chat"`
 | 
						|
are as follows:
 | 
						|
```html
 | 
						|
<!-- Syntax: #**announce>** -->
 | 
						|
<a class="stream-topic" data-stream-id="9"
 | 
						|
  href="/#narrow/channel/9-announce/topic/with/214">
 | 
						|
 #announce > <em>general chat</em>
 | 
						|
</a>
 | 
						|
 | 
						|
<!-- Syntax: #**announce>**
 | 
						|
     Generated only if topic had no messages or the link was rendered
 | 
						|
     before Zulip 10.0 (feature level 347) -->
 | 
						|
<a class="stream-topic" data-stream-id="9"
 | 
						|
  href="/#narrow/channel/9-announce/topic/">
 | 
						|
 #announce > <em>general chat</em>
 | 
						|
</a>
 | 
						|
 | 
						|
<!-- Syntax: #**announce>@214** -->
 | 
						|
<a class="message-link"
 | 
						|
  href="/#narrow/channel/9-announce/topic//near/214">
 | 
						|
 #announce > <em>general chat</em> @ 💬
 | 
						|
</a>
 | 
						|
```
 | 
						|
 | 
						|
**Changes**: In Zulip 11.0 (feature level 400), the server switched
 | 
						|
its strategy for `with` URL construction to choose the latest
 | 
						|
accessible message ID in a topic. Previously, it used the oldest.
 | 
						|
 | 
						|
Before Zulip 10.0 (feature level 347), the `with` field
 | 
						|
was never used in topic link URLs generated by the server; the markup
 | 
						|
currently used only for empty topics was used for all topic links.
 | 
						|
 | 
						|
Before Zulip 10.0 (feature level 346), empty string
 | 
						|
was not a valid topic name in syntaxes for linking to topics and
 | 
						|
messages.
 | 
						|
 | 
						|
In Zulip 10.0 (feature level 319), added Markdown syntax
 | 
						|
for linking to a specific message in a conversation. Declared the
 | 
						|
`data-stream-id` field to be deprecated as detailed above.
 | 
						|
 | 
						|
In Zulip 11.0 (feature level 383), clients can decide what
 | 
						|
channel view a.stream channel link elements take you to -- i.e.,
 | 
						|
the href for those is the default behavior of the link that also
 | 
						|
encodes the channel alongside the data-stream-id field, but clients
 | 
						|
can override that default based on `web_channel_default_view` setting.
 | 
						|
 | 
						|
## Images
 | 
						|
 | 
						|
When a Zulip message is sent linking to an uploaded image, Zulip will
 | 
						|
generate an image preview element with the following format:
 | 
						|
 | 
						|
``` html
 | 
						|
<div class="message_inline_image">
 | 
						|
    <a href="/user_uploads/path/to/example.png" title="example.png">
 | 
						|
        <img data-original-dimensions="1920x1080"
 | 
						|
          data-original-content-type="image/png"
 | 
						|
          src="/user_uploads/thumbnail/path/to/example.png/840x560.webp">
 | 
						|
    </a>
 | 
						|
</div>
 | 
						|
```
 | 
						|
 | 
						|
**Changes**: See [Changes to image formatting](#changes-to-image-formatting).
 | 
						|
 | 
						|
### Image-loading placeholders
 | 
						|
 | 
						|
If the server has yet to generate thumbnails for the image by
 | 
						|
the time the message is sent, the `img` element will temporarily
 | 
						|
reference a loading indicator image and have the `image-loading-placeholder`
 | 
						|
class, which clients can use to identify loading indicators and
 | 
						|
replace them with a more native loading indicator element if
 | 
						|
desired. For example:
 | 
						|
 | 
						|
``` html
 | 
						|
<div class="message_inline_image">
 | 
						|
    <a href="/user_uploads/path/to/example.png" title="example.png">
 | 
						|
        <img class="image-loading-placeholder"
 | 
						|
          data-original-dimensions="1920x1080"
 | 
						|
          data-original-content-type="image/png"
 | 
						|
          src="/path/to/spinner.png">
 | 
						|
    </a>
 | 
						|
</div>
 | 
						|
```
 | 
						|
 | 
						|
Once the server has a working thumbnail, such messages will be updated
 | 
						|
via an `update_message` event, with the `rendering_only: true` flag
 | 
						|
(telling clients not to adjust message edit history), with appropriate
 | 
						|
adjusted `rendered_content`. A client should process those events by
 | 
						|
just using the updated rendering. If thumbnailing failed, the same
 | 
						|
type of event will edit the message's rendered form to remove the
 | 
						|
image preview element, so no special client-side logic should be
 | 
						|
required to process such errors.
 | 
						|
 | 
						|
Note that in the uncommon situation that the thumbnailing system is
 | 
						|
backlogged, an individual message containing multiple image previews
 | 
						|
may be re-rendered multiple times as each image finishes thumbnailing
 | 
						|
and triggers a message update.
 | 
						|
 | 
						|
### Transcoded images
 | 
						|
 | 
						|
Image elements whose formats are not widely supported by web browsers
 | 
						|
(e.g., HEIC and TIFF) may contain a `data-transcoded-image` attribute,
 | 
						|
which specifies a high-resolution thumbnail format that clients may
 | 
						|
opt to present instead of the original image. If the
 | 
						|
`data-transcoded-image` attribute is present, clients should use the
 | 
						|
`data-original-content-type` attribute to decide whether to display the
 | 
						|
original image or use the transcoded version.
 | 
						|
 | 
						|
Transcoded images are presented with this structure in image previews:
 | 
						|
 | 
						|
``` html
 | 
						|
<div class="message_inline_image">
 | 
						|
    <a href="/user_uploads/path/to/example.heic" title="example.heic">
 | 
						|
        <img data-original-dimensions="1920x1080"
 | 
						|
          data-original-content-type="image/heic"
 | 
						|
          data-transcoded-image="1920x1080.webp"
 | 
						|
          src="/user_uploads/thumbnail/path/to/example.heic/840x560.webp">
 | 
						|
    </a>
 | 
						|
</div>
 | 
						|
```
 | 
						|
 | 
						|
### Recommended client processing of image previews
 | 
						|
 | 
						|
Clients are recommended to do the following when processing image
 | 
						|
previews:
 | 
						|
 | 
						|
- Clients that would like to use the image's aspect ratio to lay out
 | 
						|
  one or more images in the message feed may use the
 | 
						|
  `data-original-dimensions` attribute, which is present even if the
 | 
						|
  image is a placeholder spinner.  This attribute encodes the
 | 
						|
  dimensions of the original image as `{width}x{height}`.  These
 | 
						|
  dimensions are for the image as rendered, _after_ any EXIF rotation
 | 
						|
  and mirroring has been applied.
 | 
						|
- If the client would like to control the thumbnail resolution used,
 | 
						|
  it can replace the final section of the URL (`840x560.webp` in the
 | 
						|
  example above) with the `name` of its preferred format from the set
 | 
						|
  of supported formats provided by the server in the
 | 
						|
  `server_thumbnail_formats` portion of the `register`
 | 
						|
  response. Clients should not make any assumptions about what format
 | 
						|
  the server will use as the "default" thumbnail resolution, as it may
 | 
						|
  change over time.
 | 
						|
- Download button type elements should provide the original image
 | 
						|
  (encoded via the `href` of the containing `a` tag).
 | 
						|
- The content-type of the original image is provided on a
 | 
						|
  `data-original-content-type` attribute, so clients can decide if
 | 
						|
  they are capable of rendering the original image.
 | 
						|
- For images whose formats which are not widely-accepted by browsers
 | 
						|
  (e.g., HEIC and TIFF), the image may contain a
 | 
						|
  `data-transcoded-image` attribute, which specifies a high-resolution
 | 
						|
  thumbnail format which clients may use instead of the original
 | 
						|
  image.
 | 
						|
- Lightbox elements for viewing an image should be designed to
 | 
						|
  immediately display any already-downloaded thumbnail while fetching
 | 
						|
  the original-quality image or an appropriate higher-quality
 | 
						|
  thumbnail from the server, to be transparently swapped in once it is
 | 
						|
  available. Clients that would like to size the lightbox based on the
 | 
						|
  size of the original image can use the `data-original-dimensions`
 | 
						|
  attribute, as described above.
 | 
						|
- Animated images will have a `data-animated` attribute on the `img`
 | 
						|
  tag. As detailed in `server_thumbnail_formats`, both animated and
 | 
						|
  still images are available for clients to use, depending on their
 | 
						|
  preference. See, for example, the [web setting][help-previews]
 | 
						|
  to control whether animated images are autoplayed in the message
 | 
						|
  feed.
 | 
						|
- Clients should not assume that the requested format is the format
 | 
						|
  that they will receive; in rare cases where the client has an
 | 
						|
  out-of-date list of `server_thumbnail_formats`, the server will
 | 
						|
  provide an approximation of the client's requested format.  Because
 | 
						|
  of this, clients should not assume that the pixel dimensions or file
 | 
						|
  format match what they requested.
 | 
						|
- No other processing of the URLs is recommended.
 | 
						|
 | 
						|
### Changes to image formatting
 | 
						|
 | 
						|
**In Zulip 10.0** (feature level 336), added
 | 
						|
`data-original-content-type` attribute to convey the type of the
 | 
						|
original image, and optional `data-transcoded-image` attribute for
 | 
						|
images with formats which are not widely supported by browsers.
 | 
						|
 | 
						|
**In Zulip 9.2** (feature levels 278-279, and 287+), added
 | 
						|
`data-original-dimensions` to the `image-loading-placeholder` spinner
 | 
						|
images, containing the dimensions of the original image.
 | 
						|
 | 
						|
**In Zulip 9.0** (feature level 276), added `data-original-dimensions`
 | 
						|
attribute to images that have been thumbnailed, containing the
 | 
						|
dimensions of the full-size version of the image. Thumbnailing itself
 | 
						|
was reintroduced at feature level 275.
 | 
						|
 | 
						|
Previously, with the exception of Zulip servers that used the beta
 | 
						|
Thumbor-based implementation years ago, all image previews in Zulip
 | 
						|
messages were not thumbnailed; the `a` tag and the `img` tag would both
 | 
						|
point to the original image.
 | 
						|
 | 
						|
Clients that correctly implement the current API should handle
 | 
						|
Thumbor-based older thumbnails correctly, as long as they do not
 | 
						|
assume that `data-original-dimensions` is present. Clients should not
 | 
						|
assume that messages sent prior to the introduction of thumbnailing
 | 
						|
have been re-rendered to use the new format or have thumbnails
 | 
						|
available.
 | 
						|
 | 
						|
## Video embeddings and previews
 | 
						|
 | 
						|
When a Zulip message is sent linking to an uploaded video, Zulip may
 | 
						|
generate a video preview element with the following format.
 | 
						|
 | 
						|
 | 
						|
``` html
 | 
						|
<div class="message_inline_image message_inline_video">
 | 
						|
  <a href="/user_uploads/path/to/video.mp4">
 | 
						|
    <video preload="metadata" src="/user_uploads/path/to/video.mp4">
 | 
						|
    </video>
 | 
						|
  </a>
 | 
						|
</div>
 | 
						|
```
 | 
						|
 | 
						|
## Audio Players
 | 
						|
 | 
						|
When the Markdown media syntax is used with an uploaded file with an
 | 
						|
audio `Content-Type`, Zulip will generate an HTML5 `<audio>` player
 | 
						|
element. Supported MIME types are currently `audio/aac`, `audio/flac`,
 | 
						|
`audio/mpeg`, and `audio/wav`.
 | 
						|
 | 
						|
For example, `[file.mp3](/user_uploads/path/to/file.mp3)` renders as:
 | 
						|
 | 
						|
``` html
 | 
						|
<audio controls preload="metadata"
 | 
						|
  src="/user_uploads/path/to/file.mp3" title="file.mp3">
 | 
						|
</audio>
 | 
						|
```
 | 
						|
 | 
						|
If the Zulip server has rewritten the URL of the audio file, it will
 | 
						|
provide the URL in a `data-original-url` parameter. The Zulip server
 | 
						|
does this for all non-uploaded file audio URLs.
 | 
						|
 | 
						|
``` html
 | 
						|
<audio controls preload="metadata"
 | 
						|
  data-original-url="https://example.com/path/to/original/file.mp3"
 | 
						|
  src="https://zulipcdn.example.com/path/to/playable/file.mp3" title="file.mp3">
 | 
						|
</audio>
 | 
						|
```
 | 
						|
 | 
						|
Clients that cannot render an audio player are recommended to convert
 | 
						|
audio elements into a link to the original URL.
 | 
						|
 | 
						|
The Zulip server does not validate whether uploaded files with an
 | 
						|
audio `Content-Type` are actually playable.
 | 
						|
 | 
						|
**Changes**: New in Zulip 11.0 (feature level 405).
 | 
						|
 | 
						|
## Mentions and silent mentions
 | 
						|
 | 
						|
Zulip markup supports [mentioning](/help/mention-a-user-or-group)
 | 
						|
users, user groups, and a few special "wildcard" mentions (the three
 | 
						|
spellings of a channel wildcard mention: `@**all**`, `@**everyone**`,
 | 
						|
`@**channel**` and the topic wildcard mention `@**topic**`).
 | 
						|
 | 
						|
Mentions result in a message being highlighted for the target user(s),
 | 
						|
both in the UI and in notifications, and may also result in the target
 | 
						|
user(s) following the conversation, [depending on their
 | 
						|
settings](/help/follow-a-topic#follow-topics-where-you-are-mentioned).
 | 
						|
 | 
						|
Silent mentions of users or groups have none of those side effects,
 | 
						|
but nonetheless uniquely identify the user or group
 | 
						|
identified. (There's no such thing as a silent wildcard mention).
 | 
						|
 | 
						|
Permissions for mentioning users work as follows:
 | 
						|
 | 
						|
- Any user can mention any other user, though mentions by [muted
 | 
						|
users](/help/mute-a-user) are automatically marked as read and thus do
 | 
						|
not trigger notifications or otherwise get highlighted like unread
 | 
						|
mentions.
 | 
						|
 | 
						|
- Wildcard mentions are permitted except where [organization-level
 | 
						|
restrictions](/help/restrict-wildcard-mentions) apply.
 | 
						|
 | 
						|
- User groups can be mentioned if and only if the acting user is in
 | 
						|
the `can_mention_group` group for that group. All user groups can be
 | 
						|
silently mentioned by any user.
 | 
						|
 | 
						|
- System groups, when (silently) mentioned, should be displayed using
 | 
						|
their description, not their `role:nobody` style API names; see the
 | 
						|
main [system group
 | 
						|
documentation](/api/group-setting-values#system-groups) for
 | 
						|
details. System groups can only be silently mentioned right now,
 | 
						|
because they happen to all use the empty `Nobody` group for
 | 
						|
`can_mention_group`; clients should just use `can_mention_group` to
 | 
						|
determine which groups to offer in typeahead in similar contexts.
 | 
						|
 | 
						|
- Requests to send or edit a message that are impermissible due to
 | 
						|
including a mention where the acting user does not have permission to
 | 
						|
mention the target will return an error. Mention syntax that does not
 | 
						|
correspond to a real user or group is ignored.
 | 
						|
 | 
						|
Sample markup for `@**Example User**`:
 | 
						|
 | 
						|
``` html
 | 
						|
<span class="user-mention" data-user-id="31">@Example User</span>
 | 
						|
```
 | 
						|
 | 
						|
Sample markup for `@_**Example User**`:
 | 
						|
 | 
						|
``` html
 | 
						|
<span class="user-mention silent" data-user-id="31">Example User</span>
 | 
						|
```
 | 
						|
 | 
						|
Sample markup for `@**topic**`:
 | 
						|
 | 
						|
``` html
 | 
						|
<span class="topic-mention">@topic</span>
 | 
						|
```
 | 
						|
 | 
						|
Sample markup for `@**channel**`:
 | 
						|
 | 
						|
``` html
 | 
						|
<span class="user-mention channel-wildcard-mention"
 | 
						|
  data-user-id="*">@channel</span>
 | 
						|
```
 | 
						|
 | 
						|
Sample markup for `@*support*`, assuming "support" is a valid group:
 | 
						|
``` html
 | 
						|
<span class="user-group-mention"
 | 
						|
  data-user-group-id="17">@support</span>
 | 
						|
```
 | 
						|
 | 
						|
Sample markup for `@_*support*`, assuming "support" is a valid group:
 | 
						|
``` html
 | 
						|
<span class="user-group-mention silent"
 | 
						|
  data-user-group-id="17">support</span>
 | 
						|
```
 | 
						|
 | 
						|
Sample markup for `@_*role:administrators*`:
 | 
						|
``` html
 | 
						|
<span class="user-group-mention silent"
 | 
						|
  data-user-group-id="5">Administrators</span>
 | 
						|
```
 | 
						|
 | 
						|
When processing mentions, clients should look up the user or group
 | 
						|
referenced by ID, and update the textual name for the mention to the
 | 
						|
current name for the user or group with that ID. Note that for system
 | 
						|
groups, this requires special logic to look up the user-facing name
 | 
						|
for that group; see [system
 | 
						|
groups](/api/group-setting-values#system-groups) for details.
 | 
						|
 | 
						|
**Changes**: Prior to Zulip 10.0 (feature level 333), it was not
 | 
						|
possible to silently mention [system
 | 
						|
groups](/api/group-setting-values#system-groups).
 | 
						|
 | 
						|
In Zulip 9.0 (feature level 247), `channel` was added to the supported
 | 
						|
[wildcard][help-mention-all] options used in the
 | 
						|
[mentions][help-mentions] Markdown message formatting feature.
 | 
						|
 | 
						|
## Spoilers
 | 
						|
 | 
						|
**Changes**: In Zulip 3.0 (feature level 15), added
 | 
						|
[spoilers][help-spoilers] to supported Markdown message formatting
 | 
						|
features.
 | 
						|
 | 
						|
## Removed features
 | 
						|
 | 
						|
### Removed legacy Dropbox link preview markup
 | 
						|
 | 
						|
In Zulip 11.0 (feature level 395), the Zulip server stopped generating
 | 
						|
legacy Dropbox link previews. Dropbox links are now previewed just
 | 
						|
like standard Zulip image/link previews. However, some legacy Dropbox
 | 
						|
previews may exist in existing messages.
 | 
						|
 | 
						|
Clients are recommended to prune these previews from message HTML;
 | 
						|
since they always appear after the actual link, there is no loss of
 | 
						|
information/functionality. They can be recognized via the classes
 | 
						|
`message_inline_ref`, `message_inline_image_desc`, and
 | 
						|
`message_inline_image_title`:
 | 
						|
 | 
						|
``` html
 | 
						|
<div class="message_inline_ref">
 | 
						|
    <a href="https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl=" title="Saves">
 | 
						|
        <img src="/path/to/folder_dropbox.png">
 | 
						|
    </a>
 | 
						|
    <div><div class="message_inline_image_title">Saves</div>
 | 
						|
        <desc class="message_inline_image_desc"></desc>
 | 
						|
    </div>
 | 
						|
</div>
 | 
						|
```
 | 
						|
 | 
						|
### Removed legacy avatar markup
 | 
						|
 | 
						|
In Zulip 4.0 (feature level 24), the rarely used `!avatar()`
 | 
						|
and `!gravatar()` markup syntax, which was never documented and had an
 | 
						|
inconsistent syntax, were removed.
 | 
						|
 | 
						|
## Related articles
 | 
						|
 | 
						|
* [Markdown formatting](/help/format-your-message-using-markdown)
 | 
						|
* [Send a message](/api/send-message)
 | 
						|
* [Render a message](/api/render-message)
 | 
						|
 | 
						|
[help-code]: /help/code-blocks
 | 
						|
[help-playgrounds]: /help/code-blocks#code-playgrounds
 | 
						|
[help-spoilers]: /help/spoilers
 | 
						|
[help-global-time]: /help/global-times
 | 
						|
[help-mentions]: /help/mention-a-user-or-group
 | 
						|
[help-mention-all]: /help/mention-a-user-or-group#mention-everyone-on-a-channel
 | 
						|
[help-previews]: /help/image-video-and-website-previews#configure-how-animated-images-are-played
 |