diff --git a/dist/styles.css b/dist/styles.css
index 2615609..b652e70 100644
--- a/dist/styles.css
+++ b/dist/styles.css
@@ -240,6 +240,22 @@ nav.menu-on .btn-group .btn.system, nav.item-on .btn-group .btn.system {
     margin: 2px 8px;
     user-select: none;
 }
+.menu .link-stack {
+    overflow: hidden;
+}
+.menu .link-text {
+    margin-top: 0px;
+    margin-right: 4px;
+    margin-bottom: 0px;
+    margin-left: 4px;
+    text-align: left;
+    text-overflow: ellipsis;
+    overflow: hidden;
+    flex-grow: 1;
+}
+.menu .unread-count {
+    color: var(--neutralSecondary);
+}
 
 .settings-container {
     position: fixed;
diff --git a/screenshot.jpg b/screenshot.jpg
new file mode 100644
index 0000000..d724ad0
Binary files /dev/null and b/screenshot.jpg differ
diff --git a/src/components/menu.tsx b/src/components/menu.tsx
index 95471f3..fa0e888 100644
--- a/src/components/menu.tsx
+++ b/src/components/menu.tsx
@@ -5,7 +5,7 @@ import { Nav, INavLink, INavLinkGroup } from "office-ui-fabric-react/lib/Nav"
 import { SourceGroup } from "../scripts/models/group"
 import { SourceState, RSSSource } from "../scripts/models/source"
 import { ALL } from "../scripts/models/feed"
-import { AnimationClassNames } from "@fluentui/react"
+import { AnimationClassNames, Stack } from "@fluentui/react"
 
 export type MenuProps = {
     status: boolean,
@@ -20,6 +20,8 @@ export type MenuProps = {
 }
 
 export class Menu extends React.Component<MenuProps> {
+    countOverflow = (count: number) => count >= 1000 ? "999+" : String(count)
+
     getItems = (): INavLinkGroup[] => [
         {
             links: [
@@ -31,6 +33,7 @@ export class Menu extends React.Component<MenuProps> {
                 },
                 {
                     name: intl.get("allArticles"),
+                    ariaLabel: this.countOverflow(Object.values(this.props.sources).map(s => s.unreadCount).reduce((a, b) => a + b, 0)),
                     key: ALL,
                     icon: "TextDocument",
                     onClick: this.props.allArticles,
@@ -43,13 +46,15 @@ export class Menu extends React.Component<MenuProps> {
     getGroups = (): INavLinkGroup[] => [{
         links: this.props.groups.filter(g => g.sids.length > 0).map((g, i) => {
             if (g.isMultiple) {
+                let sources = g.sids.map(sid => this.props.sources[sid])
                 return {
                     name: g.name,
+                    ariaLabel: this.countOverflow(sources.map(s => s.unreadCount).reduce((a, b) => a + b, 0)),
                     key: "g-" + i,
                     url: null,
                     isExpanded: true,
                     onClick: () => this.props.selectSourceGroup(g, "g-" + i),
-                    links: g.sids.map(sid => this.props.sources[sid]).map(this.getSource)
+                    links: sources.map(this.getSource)
                 }
             } else {
                 return this.getSource(this.props.sources[g.sids[0]])
@@ -59,6 +64,7 @@ export class Menu extends React.Component<MenuProps> {
 
     getSource = (s: RSSSource): INavLink => ({
         name: s.name,
+        ariaLabel: this.countOverflow(s.unreadCount),
         key: "s-" + s.sid,
         onClick: () => this.props.selectSource(s),
         iconProps: s.iconurl ? this.getIconStyle(s.iconurl) : null,
@@ -74,6 +80,16 @@ export class Menu extends React.Component<MenuProps> {
         }
     })
 
+    _onRenderLink = (link: INavLink): JSX.Element => {
+        return (
+            <Stack className="link-stack" horizontal grow>
+                <div className="link-text">{link.name}</div>
+                {link.ariaLabel !== "0" && <div className="unread-count">{link.ariaLabel}</div>}
+            </Stack>
+        )
+        return ;
+      };
+
     render() {
         return this.props.status && (
             <div className="menu-container" onClick={this.props.toggleMenu} style={{display: this.props.display ? "block" : "none"}}>
@@ -84,11 +100,13 @@ export class Menu extends React.Component<MenuProps> {
                     </div>
                     <div className="nav-wrapper">
                         <Nav 
+                            onRenderLink={this._onRenderLink}
                             groups={this.getItems()} 
                             selectedKey={this.props.selected} />
                         <p className={"subs-header " + AnimationClassNames.slideDownIn10}>{intl.get("menu.subscriptions")}</p>
                         <Nav 
                             selectedKey={this.props.selected}
+                            onRenderLink={this._onRenderLink}
                             groups={this.getGroups()} />
                     </div>
                 </div>
diff --git a/src/containers/context-menu-container.tsx b/src/containers/context-menu-container.tsx
index dfa3a17..e32edf0 100644
--- a/src/containers/context-menu-container.tsx
+++ b/src/containers/context-menu-container.tsx
@@ -44,7 +44,13 @@ const mapDispatchToProps = dispatch => {
         markRead: (item: RSSItem) => dispatch(markRead(item)),
         markUnread: (item: RSSItem) => dispatch(markUnread(item)),
         toggleStarred: (item: RSSItem) => dispatch(toggleStarred(item)),
-        toggleHidden: (item: RSSItem) => dispatch(toggleHidden(item)),
+        toggleHidden: (item: RSSItem) => {
+            if(!item.hasRead) {
+                dispatch(markRead(item))
+                item.hasRead = true // get around chaining error
+            }
+            dispatch(toggleHidden(item))
+        },
         switchView: (viewType: ViewType) => {
             setDefaultView(viewType)
             dispatch(switchView(viewType))
diff --git a/src/scripts/db.ts b/src/scripts/db.ts
index 05b17ca..caca713 100644
--- a/src/scripts/db.ts
+++ b/src/scripts/db.ts
@@ -20,6 +20,7 @@ export const idb = new Datastore<RSSItem>({
         if (err) window.console.log(err)
     }
 })
+idb.ensureIndex({ fieldName: "source" })
 //idb.removeIndex("id")
 //idb.update({}, {$unset: {id: true}}, {multi: true})
 //idb.remove({}, { multi: true })
\ No newline at end of file
diff --git a/src/scripts/models/source.ts b/src/scripts/models/source.ts
index 48ce2db..b593531 100644
--- a/src/scripts/models/source.ts
+++ b/src/scripts/models/source.ts
@@ -1,7 +1,7 @@
 import Parser = require("@yang991178/rss-parser")
 import * as db from "../db"
 import { rssParser, faviconPromise, ActionStatus, AppThunk } from "../utils"
-import { RSSItem, insertItems } from "./item"
+import { RSSItem, insertItems, ItemActionTypes, FETCH_ITEMS, MARK_READ, MARK_UNREAD } from "./item"
 import { SourceGroup } from "./group"
 import { saveSettings } from "./app"
 
@@ -16,6 +16,7 @@ export class RSSSource {
     name: string
     description: string
     openTarget: SourceOpenTarget
+    unreadCount: number
 
     constructor(url: string, name: string = null) {
         this.url = url
@@ -139,17 +140,35 @@ export function initSourcesFailure(err): SourceActionTypes {
     }
 }
 
+function unreadCount(source: RSSSource): Promise<RSSSource> {
+    return new Promise<RSSSource>((resolve, reject) => {
+        db.idb.count({ source: source.sid, hasRead: false }, (err, n) => {
+            if (err) {
+                reject(err)
+            } else {
+                source.unreadCount = n
+                resolve(source)
+            }
+        })
+    })
+}
+
 export function initSources(): AppThunk<Promise<void>> {
     return (dispatch) => {
         dispatch(initSourcesRequest())
         return new Promise<void>((resolve, reject) => {
-            db.sdb.find({}).sort({ sid: 1 }).exec((err, docs) => {
+            db.sdb.find({}).sort({ sid: 1 }).exec((err, sources) => {
                 if (err) {
                     dispatch(initSourcesFailure(err))
                     reject(err)
                 } else {
-                    dispatch(initSourcesSuccess(docs))
-                    resolve()
+                    let p = sources.map(s => unreadCount(s))
+                    Promise.all(p)
+                        .then(values => {
+                            dispatch(initSourcesSuccess(values))
+                            resolve()
+                        })
+                        .catch(err => reject(err))
                 }
             })
         }) 
@@ -197,6 +216,7 @@ export function addSource(url: string, name: string = null, batch = false): AppT
                             if (err) {
                                 reject(err)
                             } else {
+                                source.unreadCount = feed.items.length
                                 dispatch(addSourceSuccess(source, batch))
                                 RSSSource.checkItems(source, feed.items, db.idb)
                                     .then(items => insertItems(items))
@@ -228,7 +248,10 @@ export function updateSourceDone(source: RSSSource): SourceActionTypes {
 
 export function updateSource(source: RSSSource): AppThunk {
     return (dispatch) => {
-        db.sdb.update({ sid: source.sid }, { $set: { ...source }}, {}, err => {
+        let sourceCopy = { ...source }
+        delete sourceCopy.sid
+        delete sourceCopy.unreadCount
+        db.sdb.update({ sid: source.sid }, { $set: { ...sourceCopy }}, {}, err => {
             if (!err) {
                 dispatch(updateSourceDone(source))
             }
@@ -268,7 +291,7 @@ export function deleteSource(source: RSSSource): AppThunk {
 
 export function sourceReducer(
     state: SourceState = {},
-    action: SourceActionTypes
+    action: SourceActionTypes | ItemActionTypes
 ): SourceState {
     switch (action.type) {
         case INIT_SOURCES:
@@ -298,6 +321,40 @@ export function sourceReducer(
             delete state[action.source.sid]
             return { ...state }
         }
+        case FETCH_ITEMS: {
+            switch (action.status) {
+                case ActionStatus.Success: {
+                    let updateMap = new Map<number, number>()
+                    for (let item of action.items) {
+                        updateMap.set(
+                            item.source, 
+                            updateMap.has(item.source) ? (updateMap.get(item.source) + 1) : 1)
+                    }
+                    let nextState = {} as SourceState
+                    for (let s in state) {
+                        let sid = parseInt(s)
+                        if (updateMap.has(sid)) {
+                            nextState[sid] = {
+                                ...state[sid],
+                                unreadCount: state[sid].unreadCount + updateMap.get(sid)
+                            } as RSSSource
+                        } else {
+                            nextState[sid] = state[sid]
+                        }
+                    }
+                    return nextState
+                }
+                default: return state
+            }
+        }
+        case MARK_UNREAD:
+        case MARK_READ: return {
+            ...state,
+            [action.item.source]: {
+                ...state[action.item.source],
+                unreadCount: state[action.item.source].unreadCount + (action.type === MARK_UNREAD ? 1 : -1)
+            } as RSSSource
+        }
         default: return state
     }
 }
\ No newline at end of file