diff --git a/apps/client/src/widgets/quick_search.ts b/apps/client/src/widgets/quick_search.ts
index 094404182..2449d4bc5 100644
--- a/apps/client/src/widgets/quick_search.ts
+++ b/apps/client/src/widgets/quick_search.ts
@@ -93,6 +93,8 @@ interface QuickSearchResponse {
         highlightedNotePathTitle: string;
         contentSnippet?: string;
         highlightedContentSnippet?: string;
+        attributeSnippet?: string;
+        highlightedAttributeSnippet?: string;
         icon: string;
     }>;
     error: string;
@@ -241,7 +243,12 @@ export default class QuickSearchWidget extends BasicWidget {
                         ${result.highlightedNotePathTitle}
                     `;
                 
-                // Add content snippet below the title if available
+                // Add attribute snippet (tags/attributes) below the title if available
+                if (result.highlightedAttributeSnippet) {
+                    itemHtml += `
${result.highlightedAttributeSnippet}
`;
+                }
+                
+                // Add content snippet below the attributes if available
                 if (result.highlightedContentSnippet) {
                     itemHtml += `${result.highlightedContentSnippet}
`;
                 }
diff --git a/apps/server/src/services/search/search_result.ts b/apps/server/src/services/search/search_result.ts
index 9d7aa247c..bf8a33524 100644
--- a/apps/server/src/services/search/search_result.ts
+++ b/apps/server/src/services/search/search_result.ts
@@ -35,6 +35,8 @@ class SearchResult {
     highlightedNotePathTitle?: string;
     contentSnippet?: string;
     highlightedContentSnippet?: string;
+    attributeSnippet?: string;
+    highlightedAttributeSnippet?: string;
     private fuzzyScore: number; // Track fuzzy score separately
 
     constructor(notePathArray: string[]) {
diff --git a/apps/server/src/services/search/services/search.ts b/apps/server/src/services/search/services/search.ts
index 3236b6edb..0d3592455 100644
--- a/apps/server/src/services/search/services/search.ts
+++ b/apps/server/src/services/search/services/search.ts
@@ -468,8 +468,13 @@ function extractContentSnippet(noteId: string, searchTokens: string[], maxLength
             content = striptags(content);
         }
 
-        // Normalize whitespace
-        content = content.replace(/\s+/g, " ").trim();
+        // Normalize whitespace while preserving paragraph breaks
+        // First, normalize multiple newlines to double newlines (paragraph breaks)
+        content = content.replace(/\n\s*\n/g, "\n\n");
+        // Then normalize spaces within lines
+        content = content.split('\n').map(line => line.replace(/\s+/g, " ").trim()).join('\n');
+        // Finally trim the whole content
+        content = content.trim();
 
         if (!content) {
             return "";
@@ -495,21 +500,36 @@ function extractContentSnippet(noteId: string, searchTokens: string[], maxLength
         // Extract snippet
         let snippet = content.substring(snippetStart, snippetStart + maxLength);
         
-        // Try to start/end at word boundaries
-        if (snippetStart > 0) {
-            const firstSpace = snippet.indexOf(" ");
-            if (firstSpace > 0 && firstSpace < 20) {
-                snippet = snippet.substring(firstSpace + 1);
-            }
-            snippet = "..." + snippet;
-        }
-        
-        if (snippetStart + maxLength < content.length) {
-            const lastSpace = snippet.lastIndexOf(" ");
-            if (lastSpace > snippet.length - 20) {
-                snippet = snippet.substring(0, lastSpace);
-            }
+        // If snippet contains linebreaks, limit to max 4 lines and override character limit
+        const lines = snippet.split('\n');
+        if (lines.length > 4) {
+            snippet = lines.slice(0, 4).join('\n');
+            // Add ellipsis if we truncated lines
             snippet = snippet + "...";
+        } else if (lines.length > 1) {
+            // For multi-line snippets, just limit to 4 lines (keep existing snippet)
+            snippet = lines.slice(0, 4).join('\n');
+            if (lines.length > 4) {
+                snippet = snippet + "...";
+            }
+        } else {
+            // Single line content - apply original word boundary logic
+            // Try to start/end at word boundaries
+            if (snippetStart > 0) {
+                const firstSpace = snippet.search(/\s/);
+                if (firstSpace > 0 && firstSpace < 20) {
+                    snippet = snippet.substring(firstSpace + 1);
+                }
+                snippet = "..." + snippet;
+            }
+            
+            if (snippetStart + maxLength < content.length) {
+                const lastSpace = snippet.search(/\s[^\s]*$/);
+                if (lastSpace > snippet.length - 20 && lastSpace > 0) {
+                    snippet = snippet.substring(0, lastSpace);
+                }
+                snippet = snippet + "...";
+            }
         }
 
         return snippet;
@@ -519,6 +539,90 @@ function extractContentSnippet(noteId: string, searchTokens: string[], maxLength
     }
 }
 
+function extractAttributeSnippet(noteId: string, searchTokens: string[], maxLength: number = 200): string {
+    const note = becca.notes[noteId];
+    if (!note) {
+        return "";
+    }
+
+    try {
+        // Get all attributes for this note
+        const attributes = note.getAttributes();
+        if (!attributes || attributes.length === 0) {
+            return "";
+        }
+
+        let matchingAttributes: Array<{name: string, value: string, type: string}> = [];
+        
+        // Look for attributes that match the search tokens
+        for (const attr of attributes) {
+            const attrName = attr.name?.toLowerCase() || "";
+            const attrValue = attr.value?.toLowerCase() || "";
+            const attrType = attr.type || "";
+            
+            // Check if any search token matches the attribute name or value
+            const hasMatch = searchTokens.some(token => {
+                const normalizedToken = normalizeString(token.toLowerCase());
+                return attrName.includes(normalizedToken) || attrValue.includes(normalizedToken);
+            });
+            
+            if (hasMatch) {
+                matchingAttributes.push({
+                    name: attr.name || "",
+                    value: attr.value || "",
+                    type: attrType
+                });
+            }
+        }
+
+        if (matchingAttributes.length === 0) {
+            return "";
+        }
+
+        // Limit to 4 lines maximum, similar to content snippet logic
+        const lines: string[] = [];
+        for (const attr of matchingAttributes.slice(0, 4)) {
+            let line = "";
+            if (attr.type === "label") {
+                line = attr.value ? `#${attr.name}="${attr.value}"` : `#${attr.name}`;
+            } else if (attr.type === "relation") {
+                // For relations, show the target note title if possible
+                const targetNote = attr.value ? becca.notes[attr.value] : null;
+                const targetTitle = targetNote ? targetNote.title : attr.value;
+                line = `~${attr.name}="${targetTitle}"`;
+            }
+            
+            if (line) {
+                lines.push(line);
+            }
+        }
+
+        let snippet = lines.join('\n');
+        
+        // Apply length limit while preserving line structure
+        if (snippet.length > maxLength) {
+            // Try to truncate at word boundaries but keep lines intact
+            const truncated = snippet.substring(0, maxLength);
+            const lastNewline = truncated.lastIndexOf('\n');
+            
+            if (lastNewline > maxLength / 2) {
+                // If we can keep most content by truncating to last complete line
+                snippet = truncated.substring(0, lastNewline);
+            } else {
+                // Otherwise just truncate and add ellipsis
+                const lastSpace = truncated.lastIndexOf(' ');
+                snippet = truncated.substring(0, lastSpace > maxLength / 2 ? lastSpace : maxLength - 3);
+                snippet = snippet + "...";
+            }
+        }
+
+        return snippet;
+    } catch (e) {
+        log.error(`Error extracting attribute snippet for note ${noteId}: ${e}`);
+        return "";
+    }
+}
+
 function searchNotesForAutocomplete(query: string, fastSearch: boolean = true) {
     const searchContext = new SearchContext({
         fastSearch: fastSearch,
@@ -533,9 +637,10 @@ function searchNotesForAutocomplete(query: string, fastSearch: boolean = true) {
 
     const trimmed = allSearchResults.slice(0, 200);
 
-    // Extract content snippets
+    // Extract content and attribute snippets
     for (const result of trimmed) {
         result.contentSnippet = extractContentSnippet(result.noteId, searchContext.highlightedTokens);
+        result.attributeSnippet = extractAttributeSnippet(result.noteId, searchContext.highlightedTokens);
     }
 
     highlightSearchResults(trimmed, searchContext.highlightedTokens, searchContext.ignoreInternalAttributes);
@@ -549,6 +654,8 @@ function searchNotesForAutocomplete(query: string, fastSearch: boolean = true) {
             highlightedNotePathTitle: result.highlightedNotePathTitle,
             contentSnippet: result.contentSnippet,
             highlightedContentSnippet: result.highlightedContentSnippet,
+            attributeSnippet: result.attributeSnippet,
+            highlightedAttributeSnippet: result.highlightedAttributeSnippet,
             icon: icon ?? "bx bx-note"
         };
     });
@@ -574,7 +681,18 @@ function highlightSearchResults(searchResults: SearchResult[], highlightedTokens
         
         // Initialize highlighted content snippet
         if (result.contentSnippet) {
-            result.highlightedContentSnippet = escapeHtml(result.contentSnippet).replace(/[<{}]/g, "");
+            // Escape HTML but preserve newlines for later conversion to 
+            result.highlightedContentSnippet = escapeHtml(result.contentSnippet);
+            // Remove any stray < { } that might interfere with our highlighting markers
+            result.highlightedContentSnippet = result.highlightedContentSnippet.replace(/[<{}]/g, "");
+        }
+        
+        // Initialize highlighted attribute snippet
+        if (result.attributeSnippet) {
+            // Escape HTML but preserve newlines for later conversion to 
+            result.highlightedAttributeSnippet = escapeHtml(result.attributeSnippet);
+            // Remove any stray < { } that might interfere with our highlighting markers
+            result.highlightedAttributeSnippet = result.highlightedAttributeSnippet.replace(/[<{}]/g, "");
         }
     }
 
@@ -612,6 +730,16 @@ function highlightSearchResults(searchResults: SearchResult[], highlightedTokens
                     contentRegex.lastIndex += 2;
                 }
             }
+
+            // Highlight in attribute snippet
+            if (result.highlightedAttributeSnippet) {
+                const attributeRegex = new RegExp(escapeRegExp(token), "gi");
+                while ((match = attributeRegex.exec(normalizeString(result.highlightedAttributeSnippet))) !== null) {
+                    result.highlightedAttributeSnippet = wrapText(result.highlightedAttributeSnippet, match.index, token.length, "{", "}");
+                    // 2 characters are added, so we need to adjust the index
+                    attributeRegex.lastIndex += 2;
+                }
+            }
         }
     }
 
@@ -621,7 +749,17 @@ function highlightSearchResults(searchResults: SearchResult[], highlightedTokens
         }
         
         if (result.highlightedContentSnippet) {
+            // Replace highlighting markers with HTML tags
             result.highlightedContentSnippet = result.highlightedContentSnippet.replace(/{/g, "").replace(/}/g, "");
+            // Convert newlines to 
 tags for HTML display
+            result.highlightedContentSnippet = result.highlightedContentSnippet.replace(/\n/g, "
");
+        }
+        
+        if (result.highlightedAttributeSnippet) {
+            // Replace highlighting markers with HTML tags
+            result.highlightedAttributeSnippet = result.highlightedAttributeSnippet.replace(/{/g, "").replace(/}/g, "");
+            // Convert newlines to 
 tags for HTML display
+            result.highlightedAttributeSnippet = result.highlightedAttributeSnippet.replace(/\n/g, "
");
         }
     }
 }