Component Inventory
title: Component Inventory
owner: vizu
last-updated: 2026-05-16
supersedes: docs/frontend/COMPONENT-INVENTORY.md (2026-02-20)
status: canonical
Bilko Component Inventory
Organized
by Project:Atomic Design {{PROJECT_NAME}}hierarchy Version:(Brad {{VERSION}}Frost). Date:All {{DATE}}components Author: {{AUTHOR}}
Status: Draft | In Review | Approved
Reviewers: {{REVIEWERS}}
Document History
Version |
Date |
Author |
Changes |
|---|
0.1 |
{{DATE}} |
{{AUTHOR}} |
Initial draft |
1. Overview
Total components: {{N}}
Library location: src/components/
Storybook: {{https://storybook.PROJECT_NAME.example.com}}
Design source: {{Figma file URL}}
Owner team: {{TEAM_NAME}}
This inventory tracks every reusable componentlive in {{PROJECT_NAME}}apps/web/. ItVerified followsagainst Atomicfilesystem Designas categorization:of atoms → molecules → organisms → templates → pages.2026-05-16.
2. Component Hierarchy DiagramAtoms
The
smallest indivisible UI units. Wrap a single HTML element or a Radix UI primitive. All shadcn/ui atoms use graphcva TBfor subgraphvariant Pagescomposition PageLogin["LoginPage"]and PageDashboard["DashboardPage"]cn() endfor subgraphclass Templates
TplAuth["AuthLayout"]
TplApp["AppLayout"]
end
subgraph Organisms
OrgNavbar["Navbar"]
OrgSidebar["Sidebar"]
OrgDataTable["DataTable"]
OrgUserForm["UserForm"]
end
subgraph Molecules
MolFormField["FormField"]
MolCard["Card"]
MolSearchBar["SearchBar"]
MolDropdown["Dropdown"]
MolPagination["Pagination"]
end
subgraph Atoms
AtomButton["Button"]
AtomInput["Input"]
AtomBadge["Badge"]
AtomSpinner["Spinner"]
AtomAvatar["Avatar"]
AtomIcon["Icon"]
end
Pages --> Templates
Templates --> Organisms
Organisms --> Molecules
Molecules --> Atoms
TODO: Update diagram to reflect actual component tree.merging.
3.shadcn/ui Atoms (Primitivein Components)
PropertyComponent |
Value | Radix
Category |
Atom |
Status |
`{{Done |
File path |
src/components/ui/Button/Button.tsx |
Storybook |
{{URL}} |
Design ref |
{{Figma frame URL}} |
Props API:
Propprimitive |
Type |
Default |
Required |
DescriptionNotes |
variantbutton.tsx |
'primary' | 'secondary' | 'ghost' | 'danger' | 'link'@radix-ui/react-slot |
6 variants (default, destructive, outline, secondary, ghost, link), 4 sizes. 'primary'asChild | No | for Visualpolymorphic style variantrendering |
sizeinput.tsx |
native 'sm' | 'md' | 'lg'<input> |
Accepts 'md'aria-invalid | , No | aria-describedby Buttonfor sizeRHF integration |
disabledlabel.tsx |
boolean@radix-ui/react-label |
Associates with input via falsehtmlFor |
No |
Disables interaction |
loadingtextarea.tsx |
native boolean<textarea> |
false | Same No | aria Showspattern spinner,as disables clickInput |
leftIconselect.tsx |
ReactNode@radix-ui/react-select |
Keyboard nav + ARIA listbox built-in. Do not use native undefined<select> |
No |
Icon before label |
rightIconbadge.tsx |
native ReactNode<span> |
undefined | Invoice No | status, Iconmarket after labellabels |
onClickseparator.tsx |
(e: MouseEvent) => void@radix-ui/react-separator |
Semantic undefined<hr> | No | with ClickARIA handlerrole |
typeskeleton.tsx |
native 'button' | 'submit' | 'reset'<div> |
'button' | Pulse No | animation HTMLfor buttonloading typestates. Use instead of spinner for content areas |
fullWidthavatar.tsx |
boolean@radix-ui/react-avatar |
false | User No | initials 100%fallback widthwhen image unavailable |
VariantsCustom & States:
primary, secondary, ghost, danger, link × default, hover, focus, active, disabled, loading
Accessibility:
Dependencies: Icon component, Spinner component
PropertyComponent |
ValueFile |
Notes |
CategoryLocaleSwitcher |
Atomcomponents/locale-switcher.tsx |
sr-Latn / hr / bs toggle. aria-label required |
StatusTrialBanner |
{{Status}} |
File path |
src/components/ui/Input/Input.TrialBanner.tsx |
Subscription | trial Storybook | countdown {{URL}}notice |
Molecules
PropsAtoms API:composed into a functional unit. May contain local useState. No external data fetching.
shadcn/ui Molecules
PropComponent |
TypeRadix primitive |
Default |
Required |
DescriptionNotes |
typedialog.tsx |
'text' | 'email' | 'password' | 'number' | 'search' | 'tel' | 'url'@radix-ui/react-dialog |
'text' | Focus No | trap Inputon typeopen, ESC dismiss, scroll lock. Use for all modal flows |
valuedropdown-menu.tsx |
string@radix-ui/react-dropdown-menu |
— | Keyboard Yesnav, (controlled) | ARIA Inputrole="menu". valueUse for action menus, not navigation |
onChangetabs.tsx |
(e: ChangeEvent) => void@radix-ui/react-tabs |
— | ARIA Yes | role="tabpanel". ChangeUse handlerfor report views, settings sections |
placeholdersheet.tsx |
string@radix-ui/react-dialog |
'' | Slide-in No | side Placeholderpanel. textBuilt on Dialog primitive |
disabledtoast.tsx |
booleancustom |
falserole="status" | No | for Disabledinformational statetoasts, role="alert" for errors |
errorcard.tsx |
booleannative |
false | CardHeader, No | CardContent, TriggersCardTitle errorsub-components. visualStandard statecontainer |
errorMessagetable.tsx |
native string<table> |
Always include undefined<caption> | No |
Error text (also setsor aria-describedbylabel) |
for screen leftAdornment |
ReactNode |
undefined |
No |
Icon or element left of input |
rightAdornment |
ReactNode |
undefined |
No |
Icon or element right of input |
size |
'sm' | 'md' | 'lg' |
'md' |
No |
Input height/font sizereaders |
VariantsCustom & States:
default, focused, error, disabled, with-left-icon, with-right-icon
Accessibility:
Must always be paired with <label> (use FormField molecule)
Error: aria-invalid="true" + aria-describedby pointing to error message id
Password: toggle visibility button must have aria-label
3.3 BadgeMolecules
PropertyComponent |
ValueFile |
Notes |
CategoryTwoFactorDialog |
Atomcomponents/settings/TwoFactorDialog.tsx |
2FA TOTP setup and verification flow |
StatusBetaInterestDialog |
{{Status}}components/beta-interest-dialog.tsx |
Waitlist capture dialog |
File pathCreditNoteModal |
src/components/ui/Badge/Badge.CreditNoteModal.tsx |
Credit note creation (uses Dialog) |
| UpsellModal |
components/UpsellModal.tsx |
Plan upgrade prompt |
| ComplianceWidget |
components/ComplianceWidget.tsx |
Per-market compliance status badge |
| ChatMessage |
components/chatbot/ChatMessage.tsx |
AI chatbot message bubble |
| ChatInput |
components/chatbot/ChatInput.tsx |
AI chatbot text input with send |
Organisms
PropsComplex API:UI sections with their own data dependencies. May call Zustand stores or receive server-fetched data as props.
PropComponent |
TypeFile |
DefaultData source |
Required |
DescriptionNotes |
| Sidebar |
variantcomponents/sidebar.tsx |
'success' | 'warning' | 'error' | 'info' | 'neutral'useAuthStore |
'neutral' | Dark No | plum Semanticnavigation, coloractive variantroute highlighting, RBAC-aware nav items |
| TopBar |
sizecomponents/top-bar.tsx |
'sm' | 'md'useAuthStore |
'md' | User No | avatar, Badgelocale sizeswitcher, notification bell |
| ChatWidget |
dotcomponents/chatbot/ChatWidget.tsx |
booleanAnthropic SDK |
false | Floating No | AI Showsaccounting colored dot instead of textassistant |
| PausalTeaserCalculator |
childrencomponents/pausal/PausalTeaserCalculator.tsx |
ReactNodelocal state |
— | Tax Yes | estimate Badgecalculator contentfor pausal businessmen |
TODO:
Landing AddPage remaining atom components following the same patternOrganisms (Select, Checkbox, Radio, Toggle, Textarea, Avatar, Tooltip, Spinner, Divider).
4. Molecules (Composite Components)
PropertyComponent |
ValueFile |
Category |
Molecule |
StatusNavbar |
{{Status}} |
File path |
src/components/ui/FormField/FormField.landing/navbar.tsx |
Composes |
Input, Label, ErrorMessage, HelpText |
Props API:
Prop |
Type |
Default |
Required |
Description |
|---|
labelHero |
string |
— |
Yes |
Visible label text |
htmlFor |
string |
— |
Yes |
Links label to input id |
error |
string |
undefined |
No |
Error message text |
helpText |
string |
undefined |
No |
Helper text below input |
required |
boolean |
false |
No |
Shows required indicator |
children |
ReactNode |
— |
Yes |
Input component |
Accessibility: Label always associated with input via htmlFor/id pair.
4.2 Card
Property |
Value |
|---|
Category |
Molecule |
Status |
{{Status}} |
File path |
src/components/ui/Card/Card.tsx |
Props API:
Prop |
Type |
Default |
Required |
Description |
|---|
variant |
'default' | 'bordered' | 'elevated' |
'default' |
No |
Visual style |
padding |
'sm' | 'md' | 'lg' | 'none' |
'md' |
No |
Internal padding |
as |
ElementType |
'div' |
No |
Polymorphic render element |
children |
ReactNode |
— |
Yes |
Card content |
Sub-components: Card.Header, Card.Body, Card.Footer
TODO: Add remaining molecule components: Modal, Dropdown, Table, Pagination, Toast, SearchBar, Breadcrumb, Tabs, Accordion, DatePicker.
5. Organisms (Complex Components)
5.1 DataTable
Property |
Value |
|---|
Category |
Organism |
Status |
{{Status}} |
File path |
src/components/features/DataTable/DataTable.landing/hero.tsx |
Dependencies |
Table (molecule), Pagination, SearchBar, Spinner, Badge |
Features:
Sortable columns (client + server-side)
Pagination (configurable page sizes)
Row selection (single + multi)
Column visibility toggle
Export action slot
Loading skeleton state
Empty state slot
Row action slot (per-row dropdown)
TODO: Document full props API for DataTable.
5.2 Navigation / Sidebar
Property |
Value |
|---|
Category |
Organism |
StatusFeatures |
{{Status}}components/landing/features.tsx |
File pathTestimonials |
src/components/layouts/Sidebar/Sidebar.landing/testimonials.tsx |
TODO: Add remaining organism components.
6. Shared Hooks / Composables Inventory
Hook |
File |
Purpose |
Used By |
|---|
useDebounce |
src/hooks/useDebounce.ts |
Debounce value changes |
SearchBar, Input |
useLocalStoragePricing |
src/hooks/useLocalStorage.tscomponents/landing/pricing.tsx |
Persistent local state |
Theme, preferences |
useMediaQueryFooter |
src/hooks/useMediaQuery.ts |
Responsive breakpoint checks |
Layout components |
useClickOutside |
src/hooks/useClickOutside.ts |
Close on outside click |
Dropdown, Modal |
useFocusTrap |
src/hooks/useFocusTrap.ts |
Trap focus inside element |
Modal, Drawer |
useToast |
src/hooks/useToast.ts |
Trigger toast notifications |
Global |
usePermission |
src/hooks/usePermission.ts |
Check user permissions |
Auth-gated components |
{{HOOK_NAME}} |
{{PATH}} |
{{PURPOSE}} |
{{CONSUMERS}}components/landing/footer.tsx |
7. Third-Party Component UsageTemplates
Route layouts that define the page skeleton. No data logic — only layout composition.
PackageTemplate |
VersionFile |
Components Used |
Wrapping StrategyNotes |
| Dashboard Layout |
{{@radix-ui/react-dialog}}app/(dashboard)/layout.tsx |
{{1.x}} | Sidebar Modal+ base | TopBar Wrapped in+ src/components/ui/Modal<main — custom styling |
{{@radix-ui/react-select}} |
{{2.x}} |
Select base |
Wrapped in src/components/ui/Selectid="main-content"> |
| Legal Layout |
{{react-hook-form}}app/(legal)/layout.tsx |
{{7.x}} | Simple Formcentered state | layout, Usedno directly + FormField wrappersidebar |
| Root Layout |
{{recharts}}app/layout.tsx |
{{2.x}}<html lang> | , Charts | font Wrappedloading, inglobal src/components/charts/providers (QueryProvider, AuthProvider) |
Policy:
NeverComposition usePatterns
third-partyPattern components directly in feature code1 — alwaysIcon-only wrapButton
inEvery localicon-only componentbutton toMUST controlhave APIaria-label. surfaceThe andicon allowitself futuremust swap.be aria-hidden.
8. Component Deprecation Process
Active<Button →variant="ghost" Deprecatedsize="icon" (soft)aria-label="Ukloni →stavku">
Deprecated<X (hard)className="h-4 →w-4" Removedaria-hidden="true" />
</Button>
Pattern 2 — Stage | RSC Action+ Required | Client
Boundary Split
Keep
data Deprecated (soft) |
Add @deprecated JSDoc comment, console warningfetching in dev,the migrationRSC guideparent; interactive behavior in Storybook | the
Client child.
Deprecated// RSC parent — no "use client"
export default async function InvoiceDetailPage({ params }: { params: { id: string } }) {
const invoice = await fetchInvoice(params.id)
return <InvoiceDetailClient invoice={invoice} />
}
// Client child
;('use client')
export function InvoiceDetailClient({ invoice }: { invoice: Invoice }) {
const [status, setStatus] = useState(invoice.status)
// interactive status changes, optimistic updates
}
Pattern 3 — Loading Skeleton via Suspense
export default function InvoicesPage() {
return (hard)
|
TypeScript<Suspense fallback={<TableSkeleton rows={10} />}>
<InvoiceTableServer />
</Suspense>
)
}
Pattern 4 — @deprecatedcva annotationCustom triggersVariant
IDEimport warning,{ addedcva } from 'class-variance-authority'
const statusBadge = cva('inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium', {
variants: {
status: {
paid: 'bg-green-100 text-green-800',
pending: 'bg-yellow-100 text-yellow-800',
overdue: 'bg-red-100 text-red-800',
draft: 'bg-gray-100 text-gray-600',
},
},
})
export function InvoiceStatusBadge({ status }: { status: InvoiceStatus }) {
return <span className={statusBadge({ status })}>{statusLabel[status]}</span>
}
OPEN QUESTION OQ-4: packages/ui/ is an empty scaffold. When should components graduate from apps/web/components/ to removalthe milestone | shared
package? Recommended Removed | trigger: Deletewhen component,apps/landing-hr updateor CHANGELOG,apps/landing-ba runneeds codemodthe ifsame available | component
(currently duplicating
landing Deprecation notice minimum period: 2 sprint cycles before hard removal.organisms).
TODO:
Link to CHANGELOG.md for tracked deprecations.
Approval
Role |
Name |
Date |
Signature |
|---|
Author |
|
|
|
Frontend Lead |
|
|
|
Design System Owner |
|
|
|