Theme options

July 14, 2026 ยท View on GitHub

Concord reads theme.toml beside config.toml and keymap.toml. Named UI Highlight Groups control colors and text modifiers, while [ui.border] controls border shapes. Every group and field is optional.

[highlight.Normal]
foreground = "terminal_default"
background = "terminal_default"

[highlight.FocusBorder]
foreground = "light_magenta"

[highlight.ComposerPickerBorder]
link = "FocusBorder"

[highlight.Selection]
background = "none"

[ui.border]
default = "plain"
composer = "rounded"

Group fields

FieldTypeMeaning
linkgroup name or "none"Inherit unset fields from another known group, or detach the built-in link.
foregroundcolor or "none"Text, marker, or border color; none clears the foreground after inheritance.
backgroundcolor or "none"Cell background color; none clears the background after inheritance.
boldbooleanEnable or disable bold.
italicbooleanEnable or disable italic.
dimbooleanEnable or disable dim.
underlinebooleanEnable or disable underline.
strikethroughbooleanEnable or disable strikethrough.

A child inherits only fields it does not set. For example, FocusedPaneBorder inherits the foreground from FocusBorder and adds bold. Setting bold = false explicitly removes inherited bold. A direct field on a child wins over the linked group. foreground = "none" and background = "none" clear that channel after inheritance.

Links may point forward or backward. Link cycles warn and ignore cyclic inheritance instead of stopping startup. Group and field names are exact and case-sensitive. Unknown groups, unknown fields, wrong field types, invalid colors, invalid border shapes, and invalid links warn and are ignored one leaf at a time. Valid sibling fields still apply. Run concord --check-config to see warnings.

Colors

Supported values are none, terminal_default, the 16 canonical ANSI names, or a six-digit RGB value with an optional #.

black, red, green, yellow, blue, magenta, cyan, gray, dark_gray, light_red, light_green, light_yellow, light_blue, light_magenta, light_cyan, white

ANSI values use the terminal palette. none removes the color channel so the style does not overwrite the cell underneath. terminal_default explicitly overwrites it with the terminal's default color. Aliases such as reset, darkgray, and bright_red are not accepted.

Border shapes

Border shape is widget geometry, so it is configured separately from Highlight Group colors and modifiers.

[ui.border]
default = "plain"
pane = "double"
composer = "rounded"
modal = "plain"
picker = "plain"
login = "plain"
message = "rounded"
forum = "rounded"
FieldBuilt-in defaultWhat it controls
defaultplainFallback for every omitted surface.
panedefaultMain pane frames.
composerroundedComposer frame.
modaldefaultModal popup frames.
pickerdefaultComposer mention, command, and emoji picker frames.
logindefaultLogin input and QR frames.
messageroundedSelected message cards.
forumroundedForum post cards.

Supported shapes are plain, rounded, double, thick, light_double_dashed, heavy_double_dashed, light_triple_dashed, heavy_triple_dashed, light_quadruple_dashed, heavy_quadruple_dashed, quadrant_inside, and quadrant_outside. When [ui.border] is absent, Concord preserves its built-in rounded Composer, message cards, and forum cards, with plain remaining surfaces. When default is set, every omitted surface uses that value. A surface field overrides it.

Border sides remain fixed. Allowing a theme to remove a side would change the inner widget area and break layout calculations. Message and forum cards use the same Ratatui glyph sets as block borders, so their configured shape stays consistent with the other surfaces.

Common semantic groups

These groups describe reusable text meaning. Component groups link to them, so one parent override can update related surfaces without coupling render code to a specific color or modifier.

GroupBuilt-in styleWhat it controls
StrongboldGeneral strong emphasis.
EmphasisitalicGeneral prose emphasis.
MuteddimLow-emphasis content.
TitleStrongParent style for titles.
HeadingStrongParent style for section headings.
DecorationMutedTree branches, dividers, and separator glyphs.
HintMutedGuidance, status notices, and overflow summaries.
DescriptionMutedSecondary descriptions and inactive detail values.
ShortcutMutedKeyboard shortcuts shown beside actions.
ActivityMutedMember and profile activity details.
ChannelTypeMarkerMutedChannel and thread type markers, including group-DM and populated-voice markers.
FieldLabelMutedLabels for detail and filter fields.
SearchContextMutedParent locations and identifiers appended to search results.
TimestampMutedParent style for timestamps.
PlaceholderMutedEmpty-state and placeholder text.
DisabledMutedDisabled controls and values.
LoadingMutedLoading-state text.
EditedMuted, italicEdited markers.
UnavailableMuted, strikethroughUnavailable content.

Linked UI groups

These component groups make broad and narrow customization work together. The link shown is the built-in default.

GroupDefault link and additionsWhat it controls
LoginTitleTitle, cyan foregroundLogin screen title.
LoginHintMutedLogin hints and secondary instructions.
PaneTitleTitleMain pane titles.
ModalTitleTitlePopup titles.
ComposerTitleTitleComposer title.
HeaderTitleTitle, cyan foregroundHeader title.
HeaderLabelMutedHeader labels such as Connected as and Voice.
MessageAuthorStrongMessage author names.
MessageTimestampTimestampMessage timestamps.
CategoryHeadingHeadingChannel category headings.
MemberGroupHeadingHeadingComplete member group headings, including counts.
MessageSecondaryMutedTyping status, reply previews, and secondary system-message content.
ForumSecondaryMutedForum age, archive, lock, and empty-activity details.
MarkdownHeading1Heading, cyan foregroundLevel-one Markdown headings.
MarkdownHeading2Heading, underlineLevel-two Markdown headings.
MarkdownHeading3HeadingLevel-three Markdown headings.
EmbedAuthorEmphasisEmbed author line.
EmbedTitleStrong, blue foregroundEmbed title.
EmbedFieldNameStrong, underlineEmbed field names.
EmbedFooterMuted, italicEmbed footer.
CodeBlockBorderBorder, dimFenced-code block border. Code text remains controlled by Syntect.
ScrollbarTrackScrollbarThumb, dimScrollbar track.
UnavailableEmojiUnavailableUnavailable emoji in Composer pickers.
HeaderErrorError, boldHeader error state.
HeaderWarningWarning, boldHeader warning state.
PaneBorderBorderUnfocused main pane borders.
FocusedPaneBorderFocusBorder, boldFocused main pane border.
LoginBorderFocusBorderLogin input and QR frames.
ComposerBorderBorderInactive Composer border.
ActiveComposerBorderFocusBorder, boldActive Composer border.
ModalBorderFocusBorder, boldModal popup frames.
ComposerPickerBorderFocusBorderMention, command, and emoji picker frames.
SelectedRowSelectionSelected rows and picker entries. Set a background on this group or Selection for filled selection.
SelectionMarkerSelectionSelection arrows in list panes and pickers, including the member pane.
ActiveFieldcyan foreground, boldActive form fields, filters, and popup commands without a filled background.
ActiveTabSelectionActive popup tabs.
MessageSelectedBorderSelectionBorderSelected message frame.
ForumBorderFocusBorderUnselected forum-post frames.
ForumSelectedBorderSelectionBorderSelected forum-post frame and marker.
ImageOverflowMessageAttachment, boldAdditional-image count labels.
BotBadgeNormal, #5865F2 background, boldMessage bot badge.
PresenceOfflineNormal, dimOffline and unknown presence.

Changing a parent updates every child that remains linked. Override a child to change one component only. Use link = "none" when a child must stop inheriting from its built-in parent.

Base and content groups

GroupBuilt-in styleWhat it controls
Normalterminal foreground and backgroundApplication canvas, normal fills, and default text base.
Borderdark gray foregroundGeneral structural borders.
FocusBordercyan foregroundParent color for focused surfaces.
Selectioncyan foreground, no background, bold, not dimParent style for selected content.
SelectionBordergreen foreground, boldParent style for framed selection.
ScrollbarThumb#AAAAAA foregroundScrollbar thumbs.
UnreadNoticecyan foreground, boldNew-message notices and forum counts.
Editingyellow foregroundFields while editing.
Reactioncyan foregroundReactions not made by the current user.
SelfReactionyellow foregroundCurrent-user reactions.
PresenceOnlinegreen foregroundOnline presence.
PresenceIdle#B48C00 foregroundIdle presence.
PresenceDndred foregroundDo Not Disturb presence.
VoiceDisabledyellow foregroundSelf-muted and self-deafened header state.
VoiceConnectionyellow foreground, boldActive voice connection header state.
FolderFallbackcyan foregroundServer folder without a Discord color.
NavigationActivegreen foreground, boldCurrently open navigation destination.
NavigationMentioned#FFA500 foregroundMentioned navigation destination.
NavigationNotifiedterminal foregroundNotified navigation destination.
NavigationUnreadterminal foregroundUnread navigation destination.
MentionBadge#FFA500 foregroundNavigation mention counts.
NotificationBadgeterminal foregroundNotification and DM unread counts.
JoinedVoiceChannelyellow foreground, boldJoined voice channel.
VoiceSpeakinggreen foreground, boldActive voice speaker.
ReplyPingEnabledcyan foregroundEnabled reply-ping state.
Tagcyan foregroundForum and picker tags.
RelationshipFriendgreen foregroundFriend state.
RelationshipIncomingyellow foregroundIncoming friend request.
RelationshipOutgoingyellow foregroundOutgoing friend request.
RelationshipBlockedred foregroundBlocked relationship.
RelationshipNoneterminal foreground, dimNo relationship.
GaugeFillcyan foregroundFilled option gauges.
MessageBodyterminal foregroundNormal message content and emoji fallback.
MarkdownQuotedark gray foregroundMarkdown quote content.
MarkdownMarkerdark gray foregroundMarkdown heading, quote, and list markers.
MessageAttachmentcyan foregroundAttachment summaries.
InlineCode#FFA500 foregroundInline code.
MessageLinkcyan foreground, underlineRaw URLs and Markdown links.
MentionSelfyellow on #5C4C23Mentions that notify the current user. Colored role mentions keep their Discord foreground.
MentionOther#C1CEF7 on #28325COther user, channel, and uncolored role mentions.
MentionRoleDiscord role foreground and derived backgroundColored role mentions that do not notify the current user. An explicit background overrides the derived background.
MentionPickerRolemagenta foregroundRole and @everyone picker fallback when Discord supplies no role color.
EmbedGutterred foregroundEmbed gutter fallback when Discord supplies no embed color.
EmbedLinkblue foreground, underlineLinks in embeds.
CommandNameMessageSecondary, #5865F2 foregroundSlash command names in system messages.
SystemThreadNamecyan foreground, boldActionable thread name in system messages.
PollAnswerSelectedterminal foreground, boldCurrent user's selected poll answer.
PollWinnerterminal foreground, boldWinning poll result.
UnreadBannerterminal foreground on #5865F2Unread-message banner.
UnreadDivider#ED4245 foregroundUnread divider line and label.
ForumPinnedBadgeyellow foreground, boldPinned forum-post badge.
Errorred foregroundFailures, destructive actions, and required indicators.
Warningyellow foregroundWarnings and pending or degraded states.
Successgreen foregroundSuccessful operations.
Infocyan foregroundInformational feedback.

The complete default configuration, including all linked component groups, is in the collapsible Default theme config section of the project README.

External colors

Nonzero Discord role and server-folder colors override related Highlight Group foregrounds. Group modifiers and configured backgrounds still apply. MentionRole.background replaces the background derived from a role color for non-notifying role mentions. Notifying role mentions use MentionSelf with the Discord role foreground.

Discord embed colors, including black, override EmbedGutter.foreground. EmbedGutter is the fallback when an embed has no color. Syntect controls fenced-code syntax colors and Concord selects its light or dark palette from Normal.background. Selected rows keep Discord and presence foregrounds.