diff --git a/pygitweb/main.py b/pygitweb/main.py
index 78aba52..888edd9 100644
--- a/pygitweb/main.py
+++ b/pygitweb/main.py
@@ -533,16 +533,20 @@ def _object_type(project: str, ref: str) -> str | None:
     return git_get_type(project, ref)
 
 
-# Common README filenames to look for at repo root (order matters: prefer README.md)
+# Common README filenames to look for (order matters: prefer README.md)
 README_CANDIDATES = ["README.md", "README", "readme.md", "readme", "Readme.md"]
 
 
-def _get_readme_at_head(project: str, head: str | None) -> tuple[str, str] | None:
-    """If a README exists at HEAD, return (filename, utf8_content). Otherwise None."""
-    if not head:
+def _get_readme_at_ref_path(
+    project: str, ref: str | None, dir_path: str | None
+) -> tuple[str, str] | None:
+    """If a README exists at ref in the given tree (dir_path), return (filename, utf8_content). Otherwise None.
+    dir_path is the tree path (e.g. '' for root, 'docs' for docs/)."""
+    if not ref:
         return None
     for name in README_CANDIDATES:
-        result = get_blob_at_ref_path(project, head, name)
+        path = f"{dir_path.strip('/')}/{name}".strip("/") if dir_path else name
+        result = get_blob_at_ref_path(project, ref, path)
         if result:
             blob, _ = result
             text = to_utf8(blob.data) or ""
@@ -550,6 +554,40 @@ def _get_readme_at_head(project: str, head: str | None) -> tuple[str, str] | Non
     return None
 
 
+def _render_readme_card(
+    project: str,
+    ref_oid: str,
+    readme_filename: str,
+    readme_content: str,
+    blob_dir: str = "",
+) -> str:
+    """Return HTML for the README card (and script for markdown). blob_dir is the current tree path for relative links."""
+    is_markdown = readme_filename.lower().endswith(".md")
+    blob_base = f"/{project}?a=blob&h={quote(ref_oid, safe='')}&f="
+    blob_base_attr = blob_base.replace("&", "&amp;").replace('"', "&quot;")
+    blob_dir_attr = blob_dir.replace("&", "&amp;").replace('"', "&quot;") if blob_dir else ""
+    if is_markdown:
+        readme_b64 = base64.b64encode(readme_content.encode("utf-8")).decode("ascii")
+        card = (
+            '<div class="card mt-3"><div class="card-header"><h2 class="card-title">README</h2></div>'
+            '<div class="card-body"><div id="readme-container" class="markdown-body" data-readme-b64="'
+            + readme_b64
+            + '" data-blob-base="'
+            + blob_base_attr
+            + '"'
+        )
+        if blob_dir_attr:
+            card += ' data-blob-dir="' + blob_dir_attr + '"'
+        card += '></div></div></div><script src="/static/readme-render.js"></script>'
+        return card
+    return (
+        '<div class="card mt-3"><div class="card-header"><h2 class="card-title">README</h2></div>'
+        '<div class="card-body"><pre class="readme-plain"><code>'
+        + esc_html(sanitize(readme_content) or "")
+        + "</code></pre></div></div>"
+    )
+
+
 def git_summary(project: str) -> HTMLResponse:
     """Project summary page. Port of git_summary."""
     descr = git_get_project_description(project) or "none"
@@ -571,28 +609,10 @@ def git_summary(project: str) -> HTMLResponse:
     pre = PREAMBLE.render(title=f"{esc_html(config.SITE_NAME)} - {project}", theme="dark", site_name=config.SITE_NAME)
     body_parts = [f"{pre}<h1>{esc_html(project)}</h1>{table}"]
 
-    readme = _get_readme_at_head(project, head)
+    readme = _get_readme_at_ref_path(project, head, "")
     if readme:
         readme_filename, readme_content = readme
-        is_markdown = readme_filename.lower().endswith(".md")
-        # Container below repo info table
-        if is_markdown:
-            readme_b64 = base64.b64encode(readme_content.encode("utf-8")).decode("ascii")
-            blob_base = f"/{project}?a=blob&h={quote(head or '', safe='')}&f="
-            blob_base_attr = blob_base.replace("&", "&amp;").replace('"', "&quot;")
-            body_parts.append(
-                '<div class="card mt-3"><div class="card-header"><h2 class="card-title">README</h2></div>'
-                '<div class="card-body"><div id="readme-container" class="markdown-body" data-readme-b64="'
-                + readme_b64 + '" data-blob-base="' + blob_base_attr + '"></div></div></div>'
-            )
-            body_parts.append('<script src="/static/readme-render.js"></script>')
-        else:
-            body_parts.append(
-                '<div class="card mt-3"><div class="card-header"><h2 class="card-title">README</h2></div>'
-                '<div class="card-body"><pre class="readme-plain"><code>'
-                + esc_html(sanitize(readme_content) or "")
-                + "</code></pre></div></div>"
-            )
+        body_parts.append(_render_readme_card(project, head or "", readme_filename, readme_content, ""))
 
     body_parts.append(POSTAMBLE)
     return HTMLResponse("".join(body_parts))
@@ -723,9 +743,15 @@ def git_tree(project: str, h: str | None, f: str | None) -> HTMLResponse:
         cols=["Name", "Type"],
         rows=rows
     )
-    return HTMLResponse(
-        f"{pre}<p class='breadcrumb'>{breadcrumb_html}</p><h1>Tree{esc_html(title_path)}</h1>{table}{POSTAMBLE}"
-    )
+    body_parts = [
+        f"{pre}<p class='breadcrumb'>{breadcrumb_html}</p><h1>Tree{esc_html(title_path)}</h1>{table}"
+    ]
+    readme = _get_readme_at_ref_path(project, ref_oid, f or "")
+    if readme:
+        readme_filename, readme_content = readme
+        body_parts.append(_render_readme_card(project, ref_oid, readme_filename, readme_content, f or ""))
+    body_parts.append(POSTAMBLE)
+    return HTMLResponse("".join(body_parts))
 
 
 def git_forks(project: str, request: Request) -> HTMLResponse:
diff --git a/pygitweb/static/readme-render.js b/pygitweb/static/readme-render.js
index ab7d3dc..d466bb1 100644
--- a/pygitweb/static/readme-render.js
+++ b/pygitweb/static/readme-render.js
@@ -7,7 +7,7 @@
     if (href.indexOf("//") === 0) return false;
     return true;
   }
-  function rewriteRelativeLinks(container, blobBase) {
+  function rewriteRelativeLinks(container, blobBase, blobDir) {
     if (!blobBase) return;
     var links = container.querySelectorAll("a[href]");
     for (var i = 0; i < links.length; i++) {
@@ -15,7 +15,8 @@
       var href = a.getAttribute("href");
       if (href && isRelativeLink(href)) {
         var path = href.replace(/^\.\//, "");
-        a.setAttribute("href", blobBase + encodeURIComponent(path));
+        var fullPath = blobDir ? blobDir + "/" + path : path;
+        a.setAttribute("href", blobBase + encodeURIComponent(fullPath));
       }
     }
   }
@@ -23,12 +24,13 @@
     var container = document.getElementById("readme-container");
     var enc = container && container.getAttribute("data-readme-b64");
     var blobBase = container && container.getAttribute("data-blob-base");
+    var blobDir = container && container.getAttribute("data-blob-dir") || "";
     if (!container || !enc || typeof showdown === "undefined") return;
     try {
       var raw = atob(enc);
       var conv = new showdown.Converter();
       container.innerHTML = conv.makeHtml(raw);
-      rewriteRelativeLinks(container, blobBase);
+      rewriteRelativeLinks(container, blobBase, blobDir);
     } catch (e) {}
   }
   if (el) {
