shadcn.io is not affiliated with official shadcn/ui
Accounting App Sidebar Block for Radix UI
A ledger in a fixed-height window: ten accounts with their net movement for FY, Q3 or September, group subtotals, a switch that hides every amount, and Reconcile for the open register.
Installation
Overview
Give a bookkeeping app its whole shell with this accounting app sidebar for React with Radix UI. A window framed by a hairline with a plus mark on each corner holds the Sidebar as a ledger: ten accounts in four groups (assets, liabilities, income and expenses), each with its net movement as a figure at the end of its row, each group with its subtotal, and a count of the entries still to match on Bank and Card. A Segment Group at the top of the rail picks the period (FY, Q3 or Sep) and every figure is worked out again; a Switch hides all the amounts, in the rail and on the page. Beside it, the top bar names the open account and holds Reconcile, a Shine Button and the only colored control. The page is that account's register: its net movement, its entry count and the entries as a table, each marked matched or to match. Reconcile matches the open account's entries, the rail's count drops and a status line says so. The rail collapses to icons with tooltips, and below the medium breakpoint it becomes a sheet. It's built from Sidebar, Segment Group, Switch, Empty, Avatar, Shine Button and Guides, with a CSS entrance only. For bookkeeping, invoicing and any app whose navigation carries balances.
FAQ
Where do the figures come from?
From ACCOUNTS, the typed accounts at the top of the file. Each account holds its entries (a date, a memo, an amount in cents and whether it is matched), and a period is a pair of ISO dates. An account's figure is the sum of its entries inside the period, a group's subtotal is the sum of its accounts, and the page's table lists the same entries, so nothing is typed twice. Change the period and the rail, the subtotals, the page and the status line all follow. Replace the array with your ledger's query and keep the rule: one list of entries, every number derived from it.
What does Hide amounts hide?
Every money figure in the window: the account amounts, the group subtotals, the net on the page and the amount column. Each becomes a row of dots on screen and the word "hidden" for screen readers, and the links' names say "amount hidden". Counts of entries stay visible, so a shoulder-surfer sees how busy an account is, not what it holds. The switch is a preference of this page only; to keep it between visits, store it with your user settings.
What stays in the page, and how do I connect it?
Everything. Reconcile marks the open account's unmatched entries for the chosen period as matched, in the block's own state; nothing is posted, and reloading starts over. When an account has nothing to match, the button stays pressable and the status line says so. Replace the handler with a call to your bank-feed or ledger API, then update the list from the result. The accounts are links to # whose handler shows the register instead of navigating. They're SidebarMenuButtons with asChild around an a element. Point them at your routes and mark the current one with isActive.
How does it work on a phone?
Below the medium breakpoint the sidebar becomes a sheet that the menu button in the top bar opens from the start edge, the right in a right-to-left layout. The period and the Hide amounts switch live in it, with the accounts. Escape or choosing an account closes the sheet and focus goes back to the menu button. The first screen is the register, with its figures and entries, and the status line at the foot says what the last choice did. The window keeps its height, and only the table scrolls.
What happens when the sidebar collapses?
The menu button or the rail along the sidebar's edge folds it to its icons. The period and the switch give way to the account icons, which stay links. Each icon keeps its link's full name for screen readers, and a tooltip shows the account and its figure on hover or focus. The provider is set with persist={false} and shortcut={false}, so the block writes no cookie and leaves Ctrl and Command with B to the page it sits on. For a full-page app, remove both to remember the state and get the shortcut, and give the provider your page's height instead of the window's.
Is it accessible?
The sidebar is a navigation landmark named after the product, with each group of accounts named by its label and the open one marked as the current page. Each link's name carries its figure and its open items ("Bank, $12,055.50, 3 to match"). The period is a labelled radio group and the switch has its own name. The register is a real table with a caption and column heads, with a "Matched" or "To match" word on every entry, so state never rests on color. One polite status line reports each change, and amounts are isolated so they read in order in a right-to-left layout.