diff --git a/plugins/catalog-react/report.api.md b/plugins/catalog-react/report.api.md
index 14c832d545..6a930671c2 100644
--- a/plugins/catalog-react/report.api.md
+++ b/plugins/catalog-react/report.api.md
@@ -277,6 +277,23 @@ export type EntityFilter = {
toQueryValue?: () => string | string[];
};
+// @public (undocumented)
+export function EntityInfoCard(props: EntityInfoCardProps): JSX_2.Element;
+
+// @public (undocumented)
+export interface EntityInfoCardProps {
+ // (undocumented)
+ children?: ReactNode;
+ // (undocumented)
+ className?: string;
+ // (undocumented)
+ footerActions?: ReactNode;
+ // (undocumented)
+ headerActions?: ReactNode;
+ // (undocumented)
+ title?: ReactNode;
+}
+
// @public
export class EntityKindFilter implements EntityFilter {
constructor(value: string, label: string);
diff --git a/plugins/catalog-react/src/components/EntityInfoCard/EntityInfoCard.test.tsx b/plugins/catalog-react/src/components/EntityInfoCard/EntityInfoCard.test.tsx
new file mode 100644
index 0000000000..9fa1e351ff
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityInfoCard/EntityInfoCard.test.tsx
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { renderInTestApp } from '@backstage/test-utils';
+import { screen } from '@testing-library/react';
+import { EntityInfoCard } from './EntityInfoCard';
+
+describe('', () => {
+ it('renders children in the card body', async () => {
+ await renderInTestApp(
+
+ Body content
+ ,
+ );
+
+ expect(screen.getByText('Body content')).toBeInTheDocument();
+ });
+
+ it('renders the title when provided', async () => {
+ await renderInTestApp(
+
+ Body
+ ,
+ );
+
+ expect(
+ screen.getByRole('heading', { name: 'My Card Title' }),
+ ).toBeInTheDocument();
+ });
+
+ it('does not render a heading when title is not provided', async () => {
+ await renderInTestApp(
+
+ Body
+ ,
+ );
+
+ expect(screen.queryByRole('heading')).not.toBeInTheDocument();
+ });
+
+ it('renders header actions next to the title', async () => {
+ await renderInTestApp(
+ Edit}>
+ Body
+ ,
+ );
+
+ expect(screen.getByRole('heading', { name: 'Title' })).toBeInTheDocument();
+ expect(screen.getByRole('button', { name: 'Edit' })).toBeInTheDocument();
+ });
+
+ it('renders footer actions when provided', async () => {
+ await renderInTestApp(
+ Next Page}>
+ Body
+ ,
+ );
+
+ expect(
+ screen.getByRole('button', { name: 'Next Page' }),
+ ).toBeInTheDocument();
+ });
+
+ it('does not render footer when footerActions is not provided', async () => {
+ const { container } = await renderInTestApp(
+
+ Body
+ ,
+ );
+
+ expect(container.querySelector('.bui-CardFooter')).not.toBeInTheDocument();
+ });
+
+ it('renders JSX titles (e.g., icon + text)', async () => {
+ await renderInTestApp(
+
+ 🏠 Home Card
+
+ }
+ >
+ Body
+ ,
+ );
+
+ expect(screen.getByText('Home Card')).toBeInTheDocument();
+ });
+});
diff --git a/plugins/catalog-react/src/components/EntityInfoCard/EntityInfoCard.tsx b/plugins/catalog-react/src/components/EntityInfoCard/EntityInfoCard.tsx
new file mode 100644
index 0000000000..29bcd59fdf
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityInfoCard/EntityInfoCard.tsx
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { ReactNode } from 'react';
+import {
+ Card,
+ CardHeader,
+ CardBody,
+ CardFooter,
+ Text,
+ Flex,
+} from '@backstage/ui';
+
+/** @public */
+export interface EntityInfoCardProps {
+ title?: ReactNode;
+ headerActions?: ReactNode;
+ footerActions?: ReactNode;
+ children?: ReactNode;
+ className?: string;
+}
+
+/** @public */
+export function EntityInfoCard(props: EntityInfoCardProps) {
+ const { title, headerActions, footerActions, children, className } = props;
+
+ return (
+
+ {title && (
+
+
+
+ {title}
+
+ {headerActions}
+
+
+ )}
+ {children}
+ {footerActions && {footerActions}}
+
+ );
+}
diff --git a/plugins/catalog-react/src/components/EntityInfoCard/index.ts b/plugins/catalog-react/src/components/EntityInfoCard/index.ts
new file mode 100644
index 0000000000..1999a228b1
--- /dev/null
+++ b/plugins/catalog-react/src/components/EntityInfoCard/index.ts
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2025 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { EntityInfoCard } from './EntityInfoCard';
+export type { EntityInfoCardProps } from './EntityInfoCard';
diff --git a/plugins/catalog-react/src/components/index.ts b/plugins/catalog-react/src/components/index.ts
index 8a1ebd1835..971d6086f7 100644
--- a/plugins/catalog-react/src/components/index.ts
+++ b/plugins/catalog-react/src/components/index.ts
@@ -35,3 +35,4 @@ export * from './EntityProcessingStatusPicker';
export * from './EntityNamespacePicker';
export * from './EntityAutocompletePicker';
export * from './MissingAnnotationEmptyState';
+export * from './EntityInfoCard';