diff --git a/apps/storybook-react-native/.storybook/storybook.requires.js b/apps/storybook-react-native/.storybook/storybook.requires.js
index 599589f3e..78e61508b 100644
--- a/apps/storybook-react-native/.storybook/storybook.requires.js
+++ b/apps/storybook-react-native/.storybook/storybook.requires.js
@@ -115,6 +115,7 @@ const getStories = () => {
"./../../packages/design-system-react-native/src/components/TextButton/TextButton.stories.tsx": require("../../../packages/design-system-react-native/src/components/TextButton/TextButton.stories.tsx"),
"./../../packages/design-system-react-native/src/components/TextField/TextField.stories.tsx": require("../../../packages/design-system-react-native/src/components/TextField/TextField.stories.tsx"),
"./../../packages/design-system-react-native/src/components/TextFieldSearch/TextFieldSearch.stories.tsx": require("../../../packages/design-system-react-native/src/components/TextFieldSearch/TextFieldSearch.stories.tsx"),
+ "./../../packages/design-system-react-native/src/components/TitleHub/TitleHub.stories.tsx": require("../../../packages/design-system-react-native/src/components/TitleHub/TitleHub.stories.tsx"),
"./../../packages/design-system-react-native/src/components/Toast/Toast.stories.tsx": require("../../../packages/design-system-react-native/src/components/Toast/Toast.stories.tsx"),
"./stories/Backgrounds.stories.tsx": require("../stories/Backgrounds.stories.tsx"),
"./stories/WalletHome.stories.tsx": require("../stories/WalletHome.stories.tsx"),
diff --git a/packages/design-system-react-native/src/components/TitleHub/README.md b/packages/design-system-react-native/src/components/TitleHub/README.md
new file mode 100644
index 000000000..61ccd0504
--- /dev/null
+++ b/packages/design-system-react-native/src/components/TitleHub/README.md
@@ -0,0 +1,283 @@
+# TitleHub
+
+TitleHub is used to display a **required** title row with an optional amount line below it, optional rows beneath that, optional inline accessories next to each row, and optional bottom label or custom bottom content.
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+## Props
+
+### `title`
+
+Title row (required). When `title` is a string, it uses `TextVariant.HeadingMd` and `TextColor.TextDefault` (merged with `titleProps`). For custom layout, pass a `ReactNode`. The row also renders when only `titleEndAccessory` is renderable (for example `title={false}` with an end accessory).
+
+Legacy **`TitleStandard`** **`topLabel`** maps to **`title`** on `TitleHub`. The old main-line value (large amount) maps to **`amount`**, not `title`.
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ------- |
+| `ReactNode` | Yes | — |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+### `titleEndAccessory`
+
+Optional node to the right of `title` in the title row (same pattern as `amountEndAccessory`).
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ----------- |
+| `ReactNode` | No | `undefined` |
+
+```tsx
+import {
+ TitleHub,
+ Box,
+ Icon,
+ IconName,
+ IconSize,
+} from '@metamask/design-system-react-native';
+
+
+
+
+ }
+ amount="$4.42"
+/>;
+```
+
+### `amount`
+
+Optional primary amount line below the title. The amount row renders when `amount` or `amountEndAccessory` is renderable. When `amount` is a string, it is wrapped with display typography (`TextVariant.DisplayLg` and `amountProps`); other `ReactNode` values render as provided.
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ----------- |
+| `ReactNode` | No | `undefined` |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+### `amountEndAccessory`
+
+Optional node rendered to the right of the amount (for example an info icon).
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ----------- |
+| `ReactNode` | No | `undefined` |
+
+```tsx
+import {
+ TitleHub,
+ Box,
+ Icon,
+ IconName,
+ IconSize,
+} from '@metamask/design-system-react-native';
+
+
+
+
+ }
+/>;
+```
+
+### `bottomLabel`
+
+Optional bottom label row with secondary typography when the value is a string (`BodySm`, medium, `TextColor.TextAlternative`). If `bottomLabel` or `bottomLabelEndAccessory` is renderable, that row is shown and `bottomAccessory` is not used.
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ----------- |
+| `ReactNode` | No | `undefined` |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+### `bottomLabelEndAccessory`
+
+Optional node to the right of `bottomLabel` in the bottom label row (same pattern as `amountEndAccessory`).
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ----------- |
+| `ReactNode` | No | `undefined` |
+
+```tsx
+import {
+ TitleHub,
+ Box,
+ Icon,
+ IconName,
+ IconSize,
+} from '@metamask/design-system-react-native';
+
+
+
+
+ }
+/>;
+```
+
+### `bottomAccessory`
+
+Optional custom bottom row when neither `bottomLabel` nor `bottomLabelEndAccessory` is renderable. Renders without default label typography; compose layout inside the node.
+
+| TYPE | REQUIRED | DEFAULT |
+| ----------- | -------- | ----------- |
+| `ReactNode` | No | `undefined` |
+
+```tsx
+import {
+ TitleHub,
+ Box,
+ BoxFlexDirection,
+ BoxAlignItems,
+ Icon,
+ IconName,
+ IconSize,
+ Text,
+ TextVariant,
+} from '@metamask/design-system-react-native';
+
+
+
+ ~$0.50 fee
+
+ }
+/>;
+```
+
+### `amountProps`
+
+Optional props merged into the amount `Text` when `amount` is a string. Use for `testID` or typography overrides.
+
+| TYPE | REQUIRED | DEFAULT |
+| -------------------- | -------- | ----------- |
+| `Partial` | No | `undefined` |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+### `titleProps`
+
+Optional props merged into the title row `Text` when `title` is a string.
+
+| TYPE | REQUIRED | DEFAULT |
+| -------------------- | -------- | ----------- |
+| `Partial` | No | `undefined` |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+### `bottomLabelProps`
+
+Optional props merged into the bottom label `Text` when `bottomLabel` is a string.
+
+| TYPE | REQUIRED | DEFAULT |
+| -------------------- | -------- | ----------- |
+| `Partial` | No | `undefined` |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+;
+```
+
+### `twClassName`
+
+Use the `twClassName` prop to add Tailwind CSS classes to the component. These classes will be merged with the component's default classes using `tw.style()`, allowing you to:
+
+- Add new styles that don't exist in the default component
+- Override the component's default styles when needed
+
+| TYPE | REQUIRED | DEFAULT |
+| -------- | -------- | ----------- |
+| `string` | No | `undefined` |
+
+```tsx
+import { TitleHub } from '@metamask/design-system-react-native';
+
+// Add additional styles
+
+
+// Override default styles
+
+```
+
+### `style`
+
+Use the `style` prop to customize the component's appearance with React Native styles. For consistent styling, prefer using `twClassName` with Tailwind classes when possible. Use `style` with `tw.style()` for conditionals or dynamic values. Other `View` props (for example `testID` and accessibility fields) are also accepted on the root container.
+
+| TYPE | REQUIRED | DEFAULT |
+| ---------------------- | -------- | ----------- |
+| `StyleProp` | No | `undefined` |
+
+```tsx
+import { useTailwind } from '@metamask/design-system-twrnc-preset';
+
+import { TitleHub } from '@metamask/design-system-react-native';
+
+export const ConditionalExample = ({ isActive }: { isActive: boolean }) => {
+ const tw = useTailwind();
+
+ return (
+
+ );
+};
+```
+
+## References
+
+[MetaMask Design System Guides](https://www.notion.so/MetaMask-Design-System-Guides-Design-f86ecc914d6b4eb6873a122b83c12940)
diff --git a/packages/design-system-react-native/src/components/TitleHub/TitleHub.stories.tsx b/packages/design-system-react-native/src/components/TitleHub/TitleHub.stories.tsx
new file mode 100644
index 000000000..dcc7ac290
--- /dev/null
+++ b/packages/design-system-react-native/src/components/TitleHub/TitleHub.stories.tsx
@@ -0,0 +1,147 @@
+import type { Meta, StoryObj } from '@storybook/react-native';
+import React from 'react';
+
+import { Box, BoxAlignItems, BoxFlexDirection } from '../Box';
+import { Icon, IconName, IconSize, IconColor } from '../Icon';
+import { Text, TextColor, FontWeight, TextVariant } from '../Text';
+
+import { TitleHub } from './TitleHub';
+import type { TitleHubProps } from './TitleHub.types';
+
+/**
+ * Pill badge: dot + label (e.g. network), for `titleEndAccessory`.
+ * TODO: Temporary until a Tag component exists.
+ *
+ * @returns Story-only testnet badge UI.
+ */
+const TestnetBadge = () => (
+
+
+
+ Testnet
+
+
+);
+
+const meta: Meta = {
+ title: 'Components/TitleHub',
+ component: TitleHub,
+ argTypes: {
+ title: {
+ control: 'text',
+ },
+ amount: {
+ control: 'text',
+ },
+ bottomLabel: {
+ control: 'text',
+ },
+ twClassName: { control: 'text' },
+ },
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+};
+
+export default meta;
+
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ title: 'Perps',
+ amount: '$336.21',
+ bottomLabel: '$336.21 available',
+ twClassName: '',
+ },
+ render: (args) => } />,
+};
+
+export const Amount: Story = {
+ render: () => ,
+};
+
+export const AmountAccessory: Story = {
+ render: () => (
+
+
+
+ }
+ />
+ ),
+};
+
+export const Title: Story = {
+ render: () => (
+
+
+
+ ),
+};
+
+export const TitleAccessory: Story = {
+ render: () => } />,
+};
+
+export const BottomLabel: Story = {
+ args: {
+ title: 'Perps',
+ amount: '$336.21',
+ bottomLabel: '$336.21 available',
+ twClassName: '',
+ },
+};
+
+export const BottomLabelAccessory: Story = {
+ render: () => (
+ }
+ />
+ ),
+};
+
+export const BottomAccessory: Story = {
+ render: () => (
+
+
+
+ Perps use isolated margin. Liquidation can occur if collateral falls
+ below maintenance.
+
+
+ }
+ />
+ ),
+};
diff --git a/packages/design-system-react-native/src/components/TitleHub/TitleHub.test.tsx b/packages/design-system-react-native/src/components/TitleHub/TitleHub.test.tsx
new file mode 100644
index 000000000..78fc97dd2
--- /dev/null
+++ b/packages/design-system-react-native/src/components/TitleHub/TitleHub.test.tsx
@@ -0,0 +1,320 @@
+// Third party dependencies.
+import { useTailwind } from '@metamask/design-system-twrnc-preset';
+import { renderHook } from '@testing-library/react-hooks';
+import { render } from '@testing-library/react-native';
+import React from 'react';
+import { Text } from 'react-native';
+
+// Internal dependencies.
+import { TitleHub } from './TitleHub';
+
+const CONTAINER_TEST_ID = 'title-hub-container';
+const AMOUNT_TEST_ID = 'title-hub-amount';
+const TITLE_ROW_TEST_ID = 'title-hub-title';
+const BOTTOM_LABEL_TEST_ID = 'title-hub-bottom-label';
+
+describe('TitleHub', () => {
+ let tw: ReturnType;
+
+ beforeAll(() => {
+ tw = renderHook(() => useTailwind()).result.current;
+ });
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ describe('rendering', () => {
+ it('renders string title', () => {
+ const { getByText } = render();
+
+ expect(getByText('Section')).toBeOnTheScreen();
+ });
+
+ it('renders string amount when provided', () => {
+ const { getByText } = render();
+
+ expect(getByText('Send')).toBeOnTheScreen();
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ });
+
+ it('renders React node amount', () => {
+ const { getByTestId } = render(
+ Custom amount}
+ />,
+ );
+
+ expect(getByTestId('title-hub-amount-node')).toBeOnTheScreen();
+ });
+
+ it('renders container with testID when provided', () => {
+ const { getByTestId } = render(
+ ,
+ );
+
+ expect(getByTestId(CONTAINER_TEST_ID)).toBeOnTheScreen();
+ });
+
+ it('forwards amountProps testID to amount Text when amount is a string', () => {
+ const { getByTestId } = render(
+ ,
+ );
+
+ expect(getByTestId(AMOUNT_TEST_ID)).toBeOnTheScreen();
+ });
+ });
+
+ describe('when title is provided', () => {
+ it('renders title and amount', () => {
+ const { getByText } = render(
+ Custom Top} amount="$4.42" />,
+ );
+
+ expect(getByText('Custom Top')).toBeOnTheScreen();
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ });
+
+ it('renders title and titleEndAccessory', () => {
+ const { getByText } = render(
+ Title extra}
+ />,
+ );
+
+ expect(getByText('Step 1')).toBeOnTheScreen();
+ expect(getByText('Title extra')).toBeOnTheScreen();
+ });
+
+ it('forwards titleProps testID to title row Text when title is a string', () => {
+ const { getByTestId } = render(
+ ,
+ );
+
+ expect(getByTestId(TITLE_ROW_TEST_ID)).toBeOnTheScreen();
+ });
+ });
+
+ describe('when title is false', () => {
+ it('does not render title node', () => {
+ const showTitle = false;
+ const { getByText, queryByTestId } = render(
+ Top : false
+ }
+ amount="$4.42"
+ />,
+ );
+
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ expect(queryByTestId('title-hub-title-slot')).not.toBeOnTheScreen();
+ });
+ });
+
+ describe('when titleEndAccessory is false', () => {
+ it('renders title only', () => {
+ const { getByText } = render(
+ ,
+ );
+
+ expect(getByText('Hi')).toBeOnTheScreen();
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ });
+ });
+
+ describe('when amount is false', () => {
+ it('does not render amount node', () => {
+ const showAmount = false;
+ const { getByText, queryByTestId } = render(
+ $1 : false
+ }
+ />,
+ );
+
+ expect(getByText('Send')).toBeOnTheScreen();
+ expect(queryByTestId('title-hub-amount-slot')).not.toBeOnTheScreen();
+ });
+ });
+
+ describe('when bottomLabel is provided', () => {
+ it('renders bottomLabel text', () => {
+ const { getByText } = render(
+ ,
+ );
+
+ expect(getByText('0.002 ETH')).toBeOnTheScreen();
+ });
+
+ it('renders bottomLabel and bottomLabelEndAccessory', () => {
+ const { getByText } = render(
+ Fee info}
+ />,
+ );
+
+ expect(getByText('0.002 ETH')).toBeOnTheScreen();
+ expect(getByText('Fee info')).toBeOnTheScreen();
+ });
+
+ it('forwards bottomLabelProps testID to bottom label Text', () => {
+ const { getByTestId } = render(
+ ,
+ );
+
+ expect(getByTestId(BOTTOM_LABEL_TEST_ID)).toBeOnTheScreen();
+ });
+ });
+
+ describe('when bottomAccessory is provided', () => {
+ it('renders bottomAccessory when bottomLabel is omitted', () => {
+ const { getByText } = render(
+ Custom Bottom}
+ />,
+ );
+
+ expect(getByText('Custom Bottom')).toBeOnTheScreen();
+ });
+ });
+
+ describe('when bottomLabel and bottomAccessory are both provided', () => {
+ it('renders only bottomLabel', () => {
+ const { getByText, queryByText } = render(
+ Accessory}
+ />,
+ );
+
+ expect(getByText('Label Priority')).toBeOnTheScreen();
+ expect(queryByText('Accessory')).not.toBeOnTheScreen();
+ });
+ });
+
+ describe('when only bottomLabelEndAccessory is provided', () => {
+ it('renders bottom label row with accessory and not bottomAccessory', () => {
+ const { getByText, queryByText } = render(
+ Only accessory}
+ bottomAccessory={Full row}
+ />,
+ );
+
+ expect(getByText('Only accessory')).toBeOnTheScreen();
+ expect(queryByText('Full row')).not.toBeOnTheScreen();
+ });
+ });
+
+ describe('when amountEndAccessory is provided', () => {
+ it('renders amount and amountEndAccessory', () => {
+ const { getByText } = render(
+ Info}
+ />,
+ );
+
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ expect(getByText('Info')).toBeOnTheScreen();
+ });
+
+ it('renders amountEndAccessory when amount is an empty string', () => {
+ const { getByText } = render(
+ Accessory only}
+ />,
+ );
+
+ expect(getByText('Accessory only')).toBeOnTheScreen();
+ });
+ });
+
+ describe('when amountEndAccessory is false', () => {
+ it('renders amount only', () => {
+ const { getByText } = render(
+ ,
+ );
+
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ });
+ });
+
+ describe('when title, amountEndAccessory, and bottomLabel are provided', () => {
+ it('renders all slots', () => {
+ const { getByText } = render(
+ Send}
+ amount="$4.42"
+ amountEndAccessory={i}
+ bottomLabel="0.002 ETH"
+ />,
+ );
+
+ expect(getByText('Send')).toBeOnTheScreen();
+ expect(getByText('$4.42')).toBeOnTheScreen();
+ expect(getByText('i')).toBeOnTheScreen();
+ expect(getByText('0.002 ETH')).toBeOnTheScreen();
+ });
+ });
+
+ describe('style and twClassName', () => {
+ it('applies custom style to root container', () => {
+ const customStyle = { opacity: 0.5 };
+ const { getByTestId } = render(
+ ,
+ );
+
+ expect(getByTestId(CONTAINER_TEST_ID)).toHaveStyle(customStyle);
+ });
+
+ it('merges twClassName with base styles', () => {
+ const { getByTestId } = render(
+ ,
+ );
+
+ const container = getByTestId(CONTAINER_TEST_ID);
+
+ expect(container).toHaveStyle(tw`bg-default`);
+ });
+ });
+});
diff --git a/packages/design-system-react-native/src/components/TitleHub/TitleHub.tsx b/packages/design-system-react-native/src/components/TitleHub/TitleHub.tsx
new file mode 100644
index 000000000..6d12393bc
--- /dev/null
+++ b/packages/design-system-react-native/src/components/TitleHub/TitleHub.tsx
@@ -0,0 +1,118 @@
+// Third party dependencies.
+import { isReactNodeRenderable } from '@metamask/design-system-shared';
+import React from 'react';
+
+// Internal dependencies.
+import { Box } from '../Box';
+import { BoxRow } from '../BoxRow';
+import { TextVariant, TextColor, FontWeight } from '../Text';
+
+import type { TitleHubProps } from './TitleHub.types';
+
+/**
+ * Displays a required title row with optional amount, inline accessories, and bottom rows in a left-aligned layout.
+ * Remaining `View` props are forwarded to the root `Box`.
+ *
+ * @param props - Component props
+ * @param props.title - Title row content (required)
+ * @param props.titleEndAccessory - Optional inline accessory to the right of `title`
+ * @param props.amount - Optional primary amount below the title
+ * @param props.amountEndAccessory - Optional inline accessory to the right of the amount
+ * @param props.bottomAccessory - Optional custom bottom row when the bottom label row is not shown
+ * @param props.bottomLabel - Optional secondary label below the amount row
+ * @param props.bottomLabelEndAccessory - Optional inline accessory to the right of `bottomLabel`
+ * @param props.titleProps - Optional props merged into title row `Text` when `title` is a string
+ * @param props.amountProps - Optional props merged into amount `Text` when `amount` is a string
+ * @param props.bottomLabelProps - Optional props merged into bottom label `Text` when `bottomLabel` is a string
+ * @param props.twClassName - Optional Tailwind classes on the root container
+ *
+ * @returns The rendered TitleHub layout.
+ */
+export const TitleHub: React.FC = ({
+ amount,
+ amountEndAccessory,
+ title,
+ titleEndAccessory,
+ bottomAccessory,
+ bottomLabel,
+ bottomLabelEndAccessory,
+ amountProps,
+ titleProps,
+ bottomLabelProps,
+ twClassName = '',
+ ...props
+}) => {
+ const amountEndAccessoryNode = isReactNodeRenderable(amountEndAccessory)
+ ? amountEndAccessory
+ : undefined;
+
+ const titleEndAccessoryNode = isReactNodeRenderable(titleEndAccessory)
+ ? titleEndAccessory
+ : undefined;
+
+ const bottomLabelEndAccessoryNode = isReactNodeRenderable(
+ bottomLabelEndAccessory,
+ )
+ ? bottomLabelEndAccessory
+ : undefined;
+
+ const renderTitleRow =
+ isReactNodeRenderable(title) || isReactNodeRenderable(titleEndAccessory);
+ const renderAmountRow =
+ isReactNodeRenderable(amount) || isReactNodeRenderable(amountEndAccessory);
+ const renderBottomLabelRow =
+ isReactNodeRenderable(bottomLabel) ||
+ isReactNodeRenderable(bottomLabelEndAccessory);
+ const renderBottomAccessory =
+ !renderBottomLabelRow && isReactNodeRenderable(bottomAccessory);
+
+ const titleRow = (
+
+ {title}
+
+ );
+
+ const amountRow = (
+
+ {amount}
+
+ );
+
+ const bottomLabelRow = (
+
+ {bottomLabel}
+
+ );
+
+ return (
+
+ {renderTitleRow ? titleRow : null}
+ {renderAmountRow ? amountRow : null}
+ {renderBottomLabelRow ? bottomLabelRow : null}
+ {renderBottomAccessory ? bottomAccessory : null}
+
+ );
+};
+
+TitleHub.displayName = 'TitleHub';
diff --git a/packages/design-system-react-native/src/components/TitleHub/TitleHub.types.ts b/packages/design-system-react-native/src/components/TitleHub/TitleHub.types.ts
new file mode 100644
index 000000000..d6c98126c
--- /dev/null
+++ b/packages/design-system-react-native/src/components/TitleHub/TitleHub.types.ts
@@ -0,0 +1,29 @@
+// Third party dependencies.
+import type { TitleHubPropsShared } from '@metamask/design-system-shared';
+import type { ViewProps } from 'react-native';
+
+// Internal dependencies.
+import type { TextProps } from '../Text/Text.types';
+
+/**
+ * TitleHub component props (React Native).
+ * Extends {@link TitleHubPropsShared} (requires `title`) with platform `Text` passthroughs, `twClassName`, and `View` props.
+ */
+export type TitleHubProps = TitleHubPropsShared & {
+ /**
+ * Optional props merged into {@link BoxHorizontal} `textProps` when `amount` is a string.
+ */
+ amountProps?: Partial;
+ /**
+ * Optional props merged into {@link BoxHorizontal} `textProps` when `title` is a string.
+ */
+ titleProps?: Partial;
+ /**
+ * Optional props merged into {@link BoxHorizontal} `textProps` when `bottomLabel` is a string.
+ */
+ bottomLabelProps?: Partial;
+ /**
+ * Optional Tailwind class name to apply to the container.
+ */
+ twClassName?: string;
+} & Omit;
diff --git a/packages/design-system-react-native/src/components/TitleHub/index.ts b/packages/design-system-react-native/src/components/TitleHub/index.ts
new file mode 100644
index 000000000..67231dc5a
--- /dev/null
+++ b/packages/design-system-react-native/src/components/TitleHub/index.ts
@@ -0,0 +1,3 @@
+export type { TitleHubPropsShared } from '@metamask/design-system-shared';
+export { TitleHub } from './TitleHub';
+export type { TitleHubProps } from './TitleHub.types';
diff --git a/packages/design-system-react-native/src/components/index.ts b/packages/design-system-react-native/src/components/index.ts
index e057985d2..3afafcfdc 100644
--- a/packages/design-system-react-native/src/components/index.ts
+++ b/packages/design-system-react-native/src/components/index.ts
@@ -204,6 +204,9 @@ export type { TextFieldSearchProps } from './TextFieldSearch';
export { TextOrChildren } from './temp-components/TextOrChildren';
export type { TextOrChildrenProps } from './temp-components/TextOrChildren';
+export { TitleHub } from './TitleHub';
+export type { TitleHubProps, TitleHubPropsShared } from './TitleHub';
+
export {
Toast,
ToastVariant,
diff --git a/packages/design-system-shared/src/index.ts b/packages/design-system-shared/src/index.ts
index c16cb2e07..4fd113a43 100644
--- a/packages/design-system-shared/src/index.ts
+++ b/packages/design-system-shared/src/index.ts
@@ -37,12 +37,15 @@ export { type BannerBasePropsShared } from './types/BannerBase';
// TextOrChildren types (ADR-0004)
export { type TextOrChildrenPropsShared } from './types/TextOrChildren';
-// BoxRow types (ADR-0004)
-export { type BoxRowPropsShared } from './types/BoxRow';
+// TitleHub types (ADR-0004)
+export { type TitleHubPropsShared } from './types/TitleHub';
// BoxColumn types (ADR-0004)
export { type BoxColumnPropsShared } from './types/BoxColumn';
+// BoxRow types (ADR-0004)
+export { type BoxRowPropsShared } from './types/BoxRow';
+
// HeaderSearch types (ADR-0003 + ADR-0004)
export {
HeaderSearchVariant,
diff --git a/packages/design-system-shared/src/types/TitleHub/TitleHub.types.ts b/packages/design-system-shared/src/types/TitleHub/TitleHub.types.ts
new file mode 100644
index 000000000..1b5afe233
--- /dev/null
+++ b/packages/design-system-shared/src/types/TitleHub/TitleHub.types.ts
@@ -0,0 +1,41 @@
+import type { ReactNode } from 'react';
+
+/**
+ * TitleHub component shared props (ADR-0004).
+ * Platform-independent properties; platform packages extend with `ViewProps` / `className`,
+ * `twClassName`, and platform `Text` prop passthroughs.
+ */
+export type TitleHubPropsShared = {
+ /**
+ * Optional primary amount line below the title (for example a fiat or token value).
+ * When a string, platforms typically wrap with large display styles via `textProps`.
+ * The amount row renders when `amount` or `amountEndAccessory` is renderable.
+ */
+ amount?: ReactNode;
+ /**
+ * Optional accessory rendered inline to the right of the amount.
+ */
+ amountEndAccessory?: ReactNode;
+ /**
+ * Title row above the optional amount (via platform `textProps` when a string). Required.
+ */
+ title: ReactNode;
+ /**
+ * Optional accessory rendered inline to the right of `title` in the title row.
+ */
+ titleEndAccessory?: ReactNode;
+ /**
+ * Optional custom bottom row when neither `bottomLabel` nor `bottomLabelEndAccessory` is renderable.
+ * Mutually exclusive with the bottom label row: only one bottom row is shown.
+ */
+ bottomAccessory?: ReactNode;
+ /**
+ * Optional bottom row with secondary label styling when a string (via platform `textProps`).
+ * If `bottomLabel` or `bottomLabelEndAccessory` is renderable, that row is shown instead of `bottomAccessory`.
+ */
+ bottomLabel?: ReactNode;
+ /**
+ * Optional accessory rendered inline to the right of `bottomLabel` in the bottom label row.
+ */
+ bottomLabelEndAccessory?: ReactNode;
+};
diff --git a/packages/design-system-shared/src/types/TitleHub/index.ts b/packages/design-system-shared/src/types/TitleHub/index.ts
new file mode 100644
index 000000000..4eb38613e
--- /dev/null
+++ b/packages/design-system-shared/src/types/TitleHub/index.ts
@@ -0,0 +1 @@
+export type { TitleHubPropsShared } from './TitleHub.types';