diff --git a/.changeset/document-table-cell-requirement.md b/.changeset/document-table-cell-requirement.md
new file mode 100644
index 0000000000..fd99de519f
--- /dev/null
+++ b/.changeset/document-table-cell-requirement.md
@@ -0,0 +1,5 @@
+---
+'@backstage/ui': patch
+---
+
+Added documentation for the table cell wrapper requirement to TSDoc comments for `Cell`, `CellText`, `CellProfile`, `ColumnConfig`, and `RowRenderFn`.
diff --git a/docs-ui/src/app/components/table/page.mdx b/docs-ui/src/app/components/table/page.mdx
index 6eb280cbe2..8d0e803bd2 100644
--- a/docs-ui/src/app/components/table/page.mdx
+++ b/docs-ui/src/app/components/table/page.mdx
@@ -42,6 +42,7 @@ import {
tableCombinedSnippet,
tableCustomRowSnippet,
tablePrimitivesSnippet,
+ tableCellRequirementSnippet,
} from './snippets';
import { ChangelogComponent } from '@/components/ChangelogComponent';
import { PageTitle } from '@/components/PageTitle';
@@ -94,6 +95,18 @@ For full control over state, use the controlled props instead:
- `search` / `onSearchChange`
- `filter` / `onFilterChange`
+### Cell Requirement
+
+Every cell rendered via `ColumnConfig.cell` (or inside a custom `RowRenderFn`) **must** return a cell component as the top-level element. The available cell components are:
+
+- **`CellText`** — displays a title with optional description and icon.
+- **`CellProfile`** — displays an avatar with a name and optional description.
+- **`Cell`** — a generic wrapper for fully custom cell content.
+
+Returning bare text, React fragments, or other elements without wrapping them in one of these cell components will break the table layout.
+
+
+
## Common Patterns
### Sorting
diff --git a/docs-ui/src/app/components/table/snippets.ts b/docs-ui/src/app/components/table/snippets.ts
index ab4bf53a58..39f266f2ea 100644
--- a/docs-ui/src/app/components/table/snippets.ts
+++ b/docs-ui/src/app/components/table/snippets.ts
@@ -57,6 +57,23 @@ const {
filter, // { value, onChange } for filters
} = useTable({ ... });`;
+// =============================================================================
+// Cell Requirement
+// =============================================================================
+
+export const tableCellRequirementSnippet = `// ✅ Correct — CellText is the top-level element
+cell: item => ;
+
+// ✅ Correct — Cell wraps custom content
+cell: item => (
+ |
+
+ |
+);
+
+// ❌ Wrong — bare text without a cell wrapper
+cell: item => {item.name};`;
+
// =============================================================================
// Common Patterns
// =============================================================================
diff --git a/packages/ui/report.api.md b/packages/ui/report.api.md
index b254b4f773..f55efe8c89 100644
--- a/packages/ui/report.api.md
+++ b/packages/ui/report.api.md
@@ -766,7 +766,7 @@ export const Cell: {
displayName: string;
};
-// @public (undocumented)
+// @public
export type CellOwnProps = {
className?: string;
};
@@ -774,7 +774,7 @@ export type CellOwnProps = {
// @public (undocumented)
export const CellProfile: (props: CellProfileProps) => JSX_2.Element;
-// @public (undocumented)
+// @public
export type CellProfileOwnProps = {
src?: string;
name?: string;
@@ -784,12 +784,12 @@ export type CellProfileOwnProps = {
className?: string;
};
-// @public (undocumented)
+// @public
export interface CellProfileProps
extends CellProfileOwnProps,
Omit {}
-// @public (undocumented)
+// @public
export interface CellProps
extends CellOwnProps,
Omit {}
@@ -800,7 +800,7 @@ export const CellText: {
displayName: string;
};
-// @public (undocumented)
+// @public
export type CellTextOwnProps = {
title: string;
description?: string;
@@ -810,7 +810,7 @@ export type CellTextOwnProps = {
className?: string;
};
-// @public (undocumented)
+// @public
export interface CellTextProps
extends CellTextOwnProps,
Omit {}
@@ -849,9 +849,8 @@ export interface CheckboxProps
// @public (undocumented)
export const Column: (props: ColumnProps) => JSX_2.Element;
-// @public (undocumented)
+// @public
export interface ColumnConfig {
- // (undocumented)
cell: (item: T) => ReactElement;
// (undocumented)
defaultWidth?: ColumnSize | null;
@@ -2068,7 +2067,7 @@ export interface RowProps
extends RowOwnProps,
Omit, keyof RowOwnProps> {}
-// @public (undocumented)
+// @public
export type RowRenderFn = (params: {
item: T;
index: number;
diff --git a/packages/ui/src/components/Table/types.ts b/packages/ui/src/components/Table/types.ts
index 0736afa05b..030ac44ae0 100644
--- a/packages/ui/src/components/Table/types.ts
+++ b/packages/ui/src/components/Table/types.ts
@@ -93,17 +93,35 @@ export interface ColumnProps
extends ColumnOwnProps,
Omit {}
-/** @public */
+/**
+ * Own props for the {@link Cell} component.
+ *
+ * @public
+ */
export type CellOwnProps = {
className?: string;
};
-/** @public */
+/**
+ * Props for the {@link Cell} component.
+ *
+ * `Cell` is a generic cell wrapper for custom cell content. When rendering
+ * cells via {@link ColumnConfig.cell} or a custom {@link RowRenderFn}, the
+ * returned element **must** be a cell component (`Cell`, `CellText`, or
+ * `CellProfile`) at the top level. Returning bare text or other elements
+ * without a cell wrapper will break the table layout.
+ *
+ * @public
+ */
export interface CellProps
extends CellOwnProps,
Omit {}
-/** @public */
+/**
+ * Own props for the {@link CellText} component.
+ *
+ * @public
+ */
export type CellTextOwnProps = {
title: string;
description?: string;
@@ -113,12 +131,25 @@ export type CellTextOwnProps = {
className?: string;
};
-/** @public */
+/**
+ * Props for the {@link CellText} component.
+ *
+ * `CellText` renders a table cell with a title and optional description. It
+ * is one of the cell components (`Cell`, `CellText`, `CellProfile`) that
+ * **must** be used as the top-level element returned from
+ * {@link ColumnConfig.cell} or a custom {@link RowRenderFn}.
+ *
+ * @public
+ */
export interface CellTextProps
extends CellTextOwnProps,
Omit {}
-/** @public */
+/**
+ * Own props for the {@link CellProfile} component.
+ *
+ * @public
+ */
export type CellProfileOwnProps = {
src?: string;
name?: string;
@@ -128,7 +159,16 @@ export type CellProfileOwnProps = {
className?: string;
};
-/** @public */
+/**
+ * Props for the {@link CellProfile} component.
+ *
+ * `CellProfile` renders a table cell with an avatar, name, and optional
+ * description. It is one of the cell components (`Cell`, `CellText`,
+ * `CellProfile`) that **must** be used as the top-level element returned
+ * from {@link ColumnConfig.cell} or a custom {@link RowRenderFn}.
+ *
+ * @public
+ */
export interface CellProfileProps
extends CellProfileOwnProps,
Omit {}
@@ -151,10 +191,27 @@ export interface PagePagination extends TablePaginationProps {
/** @public */
export type TablePaginationType = NoPagination | PagePagination;
-/** @public */
+/**
+ * Configuration for a single table column.
+ *
+ * @public
+ */
export interface ColumnConfig {
id: string;
label: string;
+ /**
+ * Renders the cell content for this column.
+ *
+ * **Important:** The returned element **must** be a cell component at the
+ * top level — either `Cell`, `CellText`, or `CellProfile`. Returning bare
+ * text, fragments, or other elements without a cell wrapper will break the
+ * table layout.
+ *
+ * @example
+ * ```tsx
+ * cell: item =>
+ * ```
+ */
cell: (item: T) => ReactElement;
header?: () => ReactElement;
isSortable?: boolean;
@@ -173,7 +230,16 @@ export interface RowConfig {
getIsDisabled?: (item: T) => boolean;
}
-/** @public */
+/**
+ * Custom render function for table rows.
+ *
+ * When using a custom row render function, each cell rendered inside the row
+ * **must** use a cell component (`Cell`, `CellText`, or `CellProfile`) as
+ * the top-level element. Returning bare text or other elements without a
+ * cell wrapper will break the table layout.
+ *
+ * @public
+ */
export type RowRenderFn = (params: {
item: T;
index: number;