diff --git a/README.md b/README.md
index d5dbe392ad738ac48588a7e1eaa7b94755ba0835..93de39f7e838d9104a873f1802883d76da5ecf44 100644
--- a/README.md
+++ b/README.md
@@ -48,7 +48,6 @@ Already implemented:
 - Add support for separate counting hard links that are shared with other
   directories or unique within the directory (issue
   [#36](https://code.blicky.net/yorhel/ncdu/issues/36)).
-  (Implemented in the data model, but not displayed in the UI yet)
 - Faster --exclude-kernfs thanks to `statfs()` caching.
 - Improved handling of Unicode and special characters.
 - Remembers item position when switching directories.
diff --git a/src/browser.zig b/src/browser.zig
index 7ed05f734919caec132c8bc5a7d3882609fdfff1..dac093b3f766e2ee9707d932b15d82f9ae505cdf 100644
--- a/src/browser.zig
+++ b/src/browser.zig
@@ -14,6 +14,7 @@ var dir_items = std.ArrayList(?*model.Entry).init(main.allocator);
 
 var dir_max_blocks: u64 = 0;
 var dir_max_size: u64 = 0;
+var dir_has_shared: bool = false;
 
 // Index into dir_items that is currently selected.
 var cursor_idx: usize = 0;
@@ -124,6 +125,7 @@ pub fn loadDir() void {
     dir_items.shrinkRetainingCapacity(0);
     dir_max_size = 1;
     dir_max_blocks = 1;
+    dir_has_shared = false;
 
     if (dir_parents.top() != model.root)
         dir_items.append(null) catch unreachable;
@@ -131,13 +133,14 @@ pub fn loadDir() void {
     while (it) |e| {
         if (e.blocks > dir_max_blocks) dir_max_blocks = e.blocks;
         if (e.size > dir_max_size) dir_max_size = e.size;
-        if (main.config.show_hidden) // fast path
-            dir_items.append(e) catch unreachable
-        else {
+        const shown = main.config.show_hidden or blk: {
             const excl = if (e.file()) |f| f.excluded else false;
             const name = e.name();
-            if (!excl and name[0] != '.' and name[name.len-1] != '~')
-                dir_items.append(e) catch unreachable;
+            break :blk !excl and name[0] != '.' and name[name.len-1] != '~';
+        };
+        if (shown) {
+            dir_items.append(e) catch unreachable;
+            if (e.dir()) |d| if (d.shared_blocks > 0 or d.shared_size > 0) { dir_has_shared = true; };
         }
         it = e.next;
     }
@@ -175,15 +178,26 @@ const Row = struct {
     }
 
     fn size(self: *Self) void {
-        defer self.col += if (main.config.si) @as(u32, 9) else 10;
+        var width = if (main.config.si) @as(u32, 9) else 10;
+        if (dir_has_shared and main.config.show_shared != .off)
+            width += 1 + width;
+        defer self.col += width;
         const item = self.item orelse return;
+        const siz = if (main.config.show_blocks) blocksToSize(item.blocks) else item.size;
+        var shr = if (item.dir()) |d| (if (main.config.show_blocks) blocksToSize(d.shared_blocks) else d.shared_size) else 0;
+        if (main.config.show_shared == .unique) shr = saturateSub(siz, shr);
+
         ui.move(self.row, self.col);
-        ui.addsize(self.bg, if (main.config.show_blocks) blocksToSize(item.blocks) else item.size);
-        // TODO: shared sizes
+        ui.addsize(self.bg, siz);
+        if (shr > 0 and main.config.show_shared != .off) {
+            self.bg.fg(.flag);
+            ui.addstr(if (main.config.show_shared == .unique) " U" else " S");
+            ui.addsize(self.bg, shr);
+        }
     }
 
     fn graph(self: *Self) void {
-        if (main.config.show_graph == .off) return;
+        if (main.config.show_graph == .off or self.col + 20 > ui.cols) return;
 
         const bar_size = std.math.max(ui.cols/7, 10);
         defer self.col += switch (main.config.show_graph) {
@@ -223,7 +237,7 @@ const Row = struct {
     }
 
     fn items(self: *Self) void {
-        if (!main.config.show_items) return;
+        if (!main.config.show_items or self.col + 10 > ui.cols) return;
         defer self.col += 7;
         const n = (if (self.item) |d| d.dir() orelse return else return).items;
         ui.move(self.row, self.col);
@@ -254,7 +268,7 @@ const Row = struct {
     }
 
     fn mtime(self: *Self) void {
-        if (!main.config.show_mtime) return;
+        if (!main.config.show_mtime or self.col + 37 > ui.cols) return;
         defer self.col += 27;
         ui.move(self.row, self.col+1);
         const ext = (if (self.item) |e| e.ext() else @as(?*model.Ext, null)) orelse dir_parents.top().entry.ext();
@@ -469,6 +483,12 @@ pub fn keyInput(ch: i32) void {
             .percent => .both,
             .both => .off,
         },
+        // TODO: This key binding is not final! I'd rather add a menu selection thing for advanced settings rather than risk running out of more keys.
+        'u' => main.config.show_shared = switch (main.config.show_shared) {
+            .off => .shared,
+            .shared => .unique,
+            .unique => .off,
+        },
 
         else => {}
     }
diff --git a/src/main.zig b/src/main.zig
index 649dc8ea2c5d7ec938ad8d13cb46f24c569506b3..1063405aef98faae00a7c15b92b63da708c59320 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -51,6 +51,7 @@ pub const config = struct {
 
     pub var show_hidden: bool = true;
     pub var show_blocks: bool = true;
+    pub var show_shared: enum { off, shared, unique } = .shared;
     pub var show_items: bool = false;
     pub var show_mtime: bool = false;
     pub var show_graph: enum { off, graph, percent, both } = .graph;