diff --git a/src/custom/SubscriptionTable/SubscriptionTable.test.tsx b/src/custom/SubscriptionTable/SubscriptionTable.test.tsx
new file mode 100644
index 000000000..d6ca54fd4
--- /dev/null
+++ b/src/custom/SubscriptionTable/SubscriptionTable.test.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import { render, screen, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom';
+import { SubscriptionTable, PlanFeature } from './SubscriptionTable';
+
+const mockFeatures: PlanFeature[] = [
+ {
+ featureName: 'Cloud Storage',
+ freePlan: '5GB',
+ teamPlan: '50GB',
+ enterprisePlan: 'Unlimited'
+ },
+ {
+ featureName: 'Priority Support',
+ freePlan: false,
+ teamPlan: true,
+ enterprisePlan: true
+ }
+];
+
+describe('SubscriptionTable Component', () => {
+ it('renders table title and feature rows correctly', () => {
+ render();
+ expect(screen.getByText('Custom Pricing Table')).toBeInTheDocument();
+ expect(screen.getByText('Cloud Storage')).toBeInTheDocument();
+ expect(screen.getByText('Priority Support')).toBeInTheDocument();
+ expect(screen.getByText('5GB')).toBeInTheDocument();
+ });
+
+ it('renders boolean indicators with accessibility labels', () => {
+ render();
+ // Assert actual accessible text labels instead of test IDs
+ expect(screen.getAllByLabelText('Included').length).toBeGreaterThan(0);
+ expect(screen.getAllByLabelText('Not included').length).toBeGreaterThan(0);
+ });
+
+ it('calls onPlanSelect when action buttons are clicked', () => {
+ const handlePlanSelect = jest.fn();
+ render();
+
+ fireEvent.click(screen.getByText('Get Started'));
+ expect(handlePlanSelect).toHaveBeenCalledWith('free');
+
+ fireEvent.click(screen.getByText('Upgrade'));
+ expect(handlePlanSelect).toHaveBeenCalledWith('team');
+
+ fireEvent.click(screen.getByText('Contact Us'));
+ expect(handlePlanSelect).toHaveBeenCalledWith('enterprise');
+ });
+
+ it('renders custom labels when passed via props', () => {
+ render(
+
+ );
+ expect(screen.getByText('Key Capabilities')).toBeInTheDocument();
+ expect(screen.getByText('Starter')).toBeInTheDocument();
+ expect(screen.getByText('Join Now')).toBeInTheDocument();
+ });
+});
diff --git a/src/custom/SubscriptionTable/SubscriptionTable.tsx b/src/custom/SubscriptionTable/SubscriptionTable.tsx
new file mode 100644
index 000000000..eb751a542
--- /dev/null
+++ b/src/custom/SubscriptionTable/SubscriptionTable.tsx
@@ -0,0 +1,145 @@
+import CheckIcon from '@mui/icons-material/Check';
+import CloseIcon from '@mui/icons-material/Close';
+import { Box, Button, Table, TableBody, TableHead, TableRow, Typography } from '@mui/material';
+import React from 'react';
+import { FeatureHeaderCell, StyledHeaderRow, StyledTableCell, StyledTableContainer } from './style';
+
+export interface PlanFeature {
+ featureName: string;
+ freePlan: boolean | string;
+ teamPlan: boolean | string;
+ enterprisePlan: boolean | string;
+}
+
+export interface SubscriptionTableProps {
+ title?: string;
+ features?: PlanFeature[];
+ onPlanSelect?: (planType: 'free' | 'team' | 'enterprise') => void;
+ featuresLabel?: string;
+ freePlanLabel?: string;
+ freePlanButtonLabel?: string;
+ teamPlanLabel?: string;
+ teamPlanButtonLabel?: string;
+ enterprisePlanLabel?: string;
+ enterprisePlanButtonLabel?: string;
+}
+
+export const SubscriptionTable: React.FC = ({
+ title = 'Subscription Plans Comparison',
+ features = [],
+ onPlanSelect,
+ featuresLabel = 'Features',
+ freePlanLabel = 'Free Plan',
+ freePlanButtonLabel = 'Get Started',
+ teamPlanLabel = 'Team Plan',
+ teamPlanButtonLabel = 'Upgrade',
+ enterprisePlanLabel = 'Enterprise Plan',
+ enterprisePlanButtonLabel = 'Contact Us'
+}) => {
+ const renderValue = (value: boolean | string) => {
+ if (typeof value === 'boolean') {
+ return value ? (
+
+ ) : (
+
+ );
+ }
+ return (
+
+ {value}
+
+ );
+ };
+
+ return (
+
+ {title && (
+
+ {title}
+
+ )}
+
+
+
+
+
+
+ {featuresLabel}
+
+
+
+
+ {freePlanLabel}
+
+
+
+
+
+
+
+ {teamPlanLabel}
+
+
+
+
+
+
+
+ {enterprisePlanLabel}
+
+
+
+
+
+
+
+
+ {features.map((row) => (
+
+
+ {row.featureName}
+
+ {renderValue(row.freePlan)}
+ {renderValue(row.teamPlan)}
+ {renderValue(row.enterprisePlan)}
+
+ ))}
+
+
+
+
+ );
+};
+
+SubscriptionTable.displayName = 'SubscriptionTable';
+
+export default SubscriptionTable;
diff --git a/src/custom/SubscriptionTable/index.ts b/src/custom/SubscriptionTable/index.ts
new file mode 100644
index 000000000..121092eba
--- /dev/null
+++ b/src/custom/SubscriptionTable/index.ts
@@ -0,0 +1 @@
+export * from './SubscriptionTable';
diff --git a/src/custom/SubscriptionTable/style.tsx b/src/custom/SubscriptionTable/style.tsx
new file mode 100644
index 000000000..c22334870
--- /dev/null
+++ b/src/custom/SubscriptionTable/style.tsx
@@ -0,0 +1,26 @@
+import { Paper, TableCell, TableRow } from '@mui/material';
+import { styled } from '@mui/material/styles';
+
+export const StyledTableContainer = styled(Paper)(({ theme }) => ({
+ borderRadius: theme.shape.borderRadius * 2,
+ overflowX: 'auto',
+ overflowY: 'hidden',
+ boxShadow: theme.shadows[2],
+ border: `1px solid ${theme.palette.divider}`
+}));
+
+export const StyledHeaderRow = styled(TableRow)(({ theme }) => ({
+ backgroundColor: theme.palette.mode === 'light' ? theme.palette.grey[50] : theme.palette.grey[900]
+}));
+
+export const StyledTableCell = styled(TableCell)(({ theme }) => ({
+ fontFamily: theme.typography.fontFamily,
+ borderColor: theme.palette.divider,
+ fontWeight: 500
+}));
+
+export const FeatureHeaderCell = styled(StyledTableCell)(({ theme }) => ({
+ fontFamily: theme.typography.fontFamily,
+ fontWeight: 700,
+ color: theme.palette.text.primary
+}));
diff --git a/src/custom/index.ts b/src/custom/index.ts
index bfc9cd185..e20c7e12a 100644
--- a/src/custom/index.ts
+++ b/src/custom/index.ts
@@ -6,5 +6,6 @@ export * from './Markdown';
export * from './Modal';
export * from './RJSFFormWrapper';
export * from './StyledAccordion';
+export * from './SubscriptionTable';
export * from './WidgetPicker';
-export * from './WidgetEmptyState';
+export * from './WidgetEmptyState';
\ No newline at end of file
diff --git a/src/custom/index.tsx b/src/custom/index.tsx
index bff31634c..6a031ee0f 100644
--- a/src/custom/index.tsx
+++ b/src/custom/index.tsx
@@ -191,5 +191,6 @@ export * from './permissions';
export * from './ResourceDetailFormatters';
export * from './RJSFFormWrapper';
export * from './ShareModal';
+export * from './SubscriptionTable';
export * from './UserSearchField';
export * from './Workspaces';
diff --git a/src/index.tsx b/src/index.tsx
index 24a87e1a1..8a0893380 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -164,3 +164,11 @@ export {
type Team as TeamPickerRecord,
type TeamSearchFieldProps
} from './custom/DashboardWidgets/GettingStartedWidget/TeamSearchField';
+
+// Explicit re-export for SubscriptionTable to prevent rollup-plugin-dts from
+// dropping the component and its types from the generated dist/index.d.ts bundle.
+export {
+ SubscriptionTable,
+ type SubscriptionTableProps,
+ type PlanFeature
+} from './custom/SubscriptionTable';