Note Display Components#
Overview#
Misskey's frontend renders notes through a hierarchy of four Vue components, each targeting a different context. All share a common composable, useNote, that centralises state and actions.
| Component | File | Use case |
|---|---|---|
MkNote | MkNote.vue | Timeline/feed rows β full interactive note |
MkNoteDetailed | MkNoteDetailed.vue | Single-note permalink view |
MkNoteSimple | MkNoteSimple.vue | Inline quote/renote target inside another note |
MkNoteSub | MkNoteSub.vue | Reply context (above a note) and reply children (below) |
Composition diagram#
MkNote / MkNoteDetailed
βββ MkNoteSub (reply parent, rendered above the article)
βββ [renote banner] (if isRenote)
βββ article
β βββ MkNoteHeader
β βββ Mfm (text)
β βββ MkMediaList, MkPoll, MkUrlPreview β¦
β βββ MkNoteSimple (inline quote β the renote target)
βββ [MkNoteDetailed only] tabs: replies | renotes | reactions
βββ MkNoteSub (each reply child)
MkNoteSimple
βββ MkNoteHeader
βββ MkSubNoteContent (text, files, polls β no actions)
MkNoteSub
βββ [if depth < 5] self
βββ MkNoteSub (recursive, depth + 1)
Component Details#
MkNote#
MkNote.vue β the standard timeline card.
- Props:
note,pinned?,mock?,withHardMute? - Visibility guard: the root
<div>is only rendered when!hardMuted && !hideByPlugin && muted === false; muted notes collapse to a dismissible banner - Renote unwrapping:
appearNote(fromuseNote) resolves the true content note; the renote banner is shown separately above the article - Inline quote:
MkNoteSimpleis rendered inside.quotewhenappearNote.renoteIdexists - Long content: collapsed to
max-height: 9emwhenisLongis true; toggled with "Show more / Show less" buttons - Performance:
content-visibility: auto(skipRenderCSS class) applied whenprefer.s.skipNoteRenderis enabled;contain: contentis always active - Keyboard shortcuts:
rreply,e/a/+react,qrenote,mmenu,v/Entertoggle CW/collapse
MkNoteDetailed#
MkNoteDetailed.vue β the permalink/detail view, rendered larger (font-size: 1.2em).
- Extra features vs MkNote: expandable conversation thread above, tabs for replies/renotes/reactions below
- Reply thread loading:
loadConversation()callsnotes/conversation;loadReplies()callsnotes/children(limit 30) - Renotes/reactions tabs: backed by
Paginatorinstances queryingnotes/renotesandnotes/reactions - isDeleted guard: the whole note body is hidden when
isDeletedis true (fromuseNotereactive state) - No hard-mute prop:
withHardMuteis not passed; detail view always shows the note if not soft-muted
MkNoteSimple#
MkNoteSimple.vue β lightweight embed for quoted/renoted content; no action buttons.
- Accepts
note: Note | null - Deleted note handling: when
noteisnull, renders a hatched "deleted note" placeholder instead of content - Delegates body rendering to
MkSubNoteContent - CW toggle is self-contained via a local
showContentref
MkNoteSub#
MkNoteSub.vue β used for reply ancestors (above notes) and reply children (in MkNoteDetailed).
- Recursive: renders itself for each child reply, up to depth 5; beyond that shows a "view more" link
- Accepts
note: Note | null:nullrenders a hatched deleted-note placeholder - Word-mute check: computed on mount via
checkWordMute - Detail mode: when
detail === true, fetches up to 5 child notes vianotes/children
Shared Logic: useNote Composable#
All note-display components (except MkNoteSimple/MkNoteSub) call useNote (composables/use-note.ts), which provides:
appearNoteβ the actual note to display (renote target ifisRenote, else the note itself)isRenoteβ determined byMisskey.note.isPureRenote()isDeletedβ reactive flag set when anoteDeletedglobal event fires for this note's ID- Mute state:
calculateMuteStatus()checks word mutes across the primary note, its reply parent, and its renote target ; returns matched words,false, or'sensitiveMute' - Hard mute: separate check against
$i.hardMutedWords - All user actions (
reply,renote,react,showMenu,clip) are gated by login status andmockprop
Edge Case: Deleted Notes in Quoted/Renoted Content#
When a renoted or quoted note is deleted, the API returns the outer renote object with renote: null:
- In
MkNote/MkNoteDetailed:isRenote && note.renote == nullrenders a hatched "deleted note" div in place of the article - In
MkNoteSimple: the prop is typedNote | null; receivingnullrenders the hatched placeholder - In
MkNoteSub: sameNote | nullcontract;nullshows the placeholder
The hatched background is applied via a repeating CSS gradient (repeating-linear-gradient(135deg, ...)) on the .deleted class, consistent across all four components.
Key Sub-Components#
| Component | Role |
|---|---|
MkNoteHeader | Avatar row with user name, timestamp, visibility icon |
MkSubNoteContent | Body text + files + polls for MkNoteSimple/MkNoteSub; handles long-content collapse |
MkReactionsViewer | Reaction emoji strip with counts |
MkMediaList | Photo/video attachments grid |
MkCwButton | Content-warning toggle button |
MkPoll | Poll choices and voting |
MkUrlPreview | Link card previews |