One component covers all three, and the default text, “No data”, fits none of them. The reader is asking a different question each time, and the description is where you answer it.
- Nothing yet. The container is new and the reader can fix that, so this is the one kind that earns an action: “No invoices yet” with a Create invoice button under it. It is also the only kind worth a full-size illustration.
- Nothing matching. The data exists and a filter or query excluded it. Say what was searched and offer the way back: “No results for ‘q4’” with a Clear filters link. A “Create” button here answers a question nobody asked and hides that the rows are one filter away.
- Nothing you are allowed to see. Rows exist and are not yours. Never let this one fall through to “No data”, which reads as a broken system or invites the reader to create a duplicate. Name the reason and, where there is one, the way to request access.
So the description cannot be a constant. Derive it from the same state that produced the emptiness: is there a query, a filter, a permission answer?