A sexy, interactive book table for your Obsidian vault.
Search, sort, drag, resize β all inside a single DataviewJS block. No plugins beyond Dataview, no build step, no dependencies.
| π Live search | Filter as you type across title, author, genre, ISBN, place and summary (debounced, so it stays snappy on big shelves). |
| Click any header to sort. Pages and Rating sort numerically, Start/End sort chronologically, everything else alphabetically. Click again to reverse. | |
| Grab a header and drop it wherever you want. | |
| π Resizable columns | Drag the right edge of any header to resize. |
| πΌοΈ Cover art | Renders cover images straight from a URL, lazy-loaded and privacy-friendly (no-referrer). |
| π Real Obsidian links | Titles open the note. Cmd/Ctrl + click opens it in a new pane. |
| ποΈ Forgiving dates | Understands YYYY-MM-DD, DD.MM.YYYY, ISO 8601, and native Dataview dates. |
| π¨ Theme-native | Uses Obsidian's own CSS variables, so it looks right in light and dark mode. |
- Obsidian
- The Dataview plugin
- JavaScript Queries enabled:
Settings β Community plugins β Dataview β Enable JavaScript Queries
β οΈ Without JavaScript Queries turned on, the block will render as plain text.
Create a new note in your vault (e.g. Library.md), then copy the entire contents of Library.md into it β including the ```dataviewjs fences.
Open the block and change the first line to the folder where your book notes live:
const SOURCE = '"π My Bookshelf"'; // β your folder, in nested quotesThe nested quotes are not a typo β Dataview needs the folder name wrapped in quotes inside the JavaScript string.
You can also target a tag instead of a folder:
const SOURCE = '#book';Every book is a normal note with frontmatter. The example template gets you started:
---
title: The Left Hand of Darkness
author: Ursula K. Le Guin
pages: 304
genre: Science Fiction
coverUrl: https://covers.openlibrary.org/b/isbn/9780441478125-L.jpg
Start π
: 2026-01-14
End π: 2026-02-02
rating: 5
place: Karhide
isbn: 9780441478125
summary: An envoy from a galactic federation visits a planet where gender is fluid.
---That's it. The table picks it up immediately.
Every property is optional, and each one accepts several spellings so it fits whatever naming convention your vault already uses.
| Column | Property (any of these) | Notes |
|---|---|---|
| Autor | author, Author |
|
| Titel | title, Title |
Falls back to the file name |
| Seiten | pages, Pages |
Sorted numerically |
| Genre | genre, Genre |
|
| Cover | coverUrl, CoverUrl, coverURL, cover |
Image URL, capped at 110Γ110 px |
| π Start | Start π
, start, started, start_date, Start Date |
Sorted chronologically |
| π End | End π, end, finished, end_date, End Date |
Sorted chronologically |
| Summary | summary, Summary |
Truncated at 200 chars; full text on hover |
| β | rating, Rating |
Sorted numerically |
| Place | place, Place |
|
| ISBN | isbn, ISBN, isbn10, ISBN10, isbn13, ISBN13 |
Rename or reorder the columns β edit the columns array near the top. The order there is the order you see on load:
{ key: "Rating", label: "β
", get: p => getFirst(p, ["rating","Rating"]) },Add your own column β one line, same shape:
{ key: "Publisher", label: "Verlag", get: p => getFirst(p, ["publisher","Publisher"]) },Change the date format β formatDate() uses Luxon tokens:
return dt ? dt.toFormat("dd.MM.yyyy") : ""; // β 02.02.2026Change the cover size β search for maxHeight in the render loop.
- Layout changes are per-session. Column order, widths and the active sort reset when the note is re-rendered. They're deliberately not written back to disk β nothing here touches your vault.
- The Cover column doesn't sort. Sorting images isn't a thing.
- Covers are loaded from the internet. If you'd rather keep everything local, point
coverUrlat a vault-relative path instead. - Source comments are in German. The code works the same in any language; translations welcome.
| Symptom | Fix |
|---|---|
| The block shows as raw code | Enable JavaScript Queries in the Dataview settings. |
| Table renders but is empty | Check SOURCE β the folder name must match exactly, emoji and all, and stay wrapped in nested quotes. |
| Covers don't show | Make sure the URL is a direct link to an image file, not to a web page showing one. |
| Dates are blank | Use YYYY-MM-DD (e.g. 2026-02-02). Quote the value if Obsidian reformats it. |
Issues and pull requests are very welcome β see CONTRIBUTING.md.
MIT Β© Emely Marie Junker