Skip to main content

Overriding the Order component

To override the default Order component, input RegularOrder to the uiOverrides: trading property in the ChartReactApp

The Order component without the Close button icon has the following properties:

interface RegularOrderProps {
readonly order: VisualOrder;
readonly className?: string;
readonly onSelect?: (id: string) => void;
readonly onDblClick?: (id: string) => void;
readonly onClick?: (id: string) => void;
readonly onDeselect?: (id: string) => void;
readonly onClose?: (id: string) => void;
readonly onDragStart?: (id: string) => void;
readonly createProtectionOrder?: (type: ProtectionOrderType, originalId: string) => void;
readonly takeProfitStopLossEnabled?: boolean;
readonly showPriceAsLabels?: boolean;
readonly horizontalLineWidth: number;
readonly isLineVisible?: boolean;
readonly onCreateOcoOrders?: () => void;
}
const OrderComponent = (props: OrderProps) => {
const {
children,
absoluteChildren,
side,
selected = false,
disabled = false,
className,
testId,
onClick,
onSelect,
onDblClick,
onDeselect,
withDeselectBtn = false,
data = {},
canCreateOCO = false,
onCreateOcoOrders,
} = props;

/* your code */

return (
<OrderContainerStyled {...dataAttrs} className={className} disabled={disabled} data-test-id={testId}>
{withDeselectBtn &&
deselectBtnTransition(
(styles, selected) =>
selected && (
<animated.div style={styles}>
<DeselectOrderButton onClick={onDeselectHandler} />
</animated.div>
),
)}
{absoluteChildren}
<OrderContainerInnerStyled onClick={onClickHandler} disabled={disabled} selected={selected}>
<Side side={side} />
{children}
{canCreateOCO &&
ocoBtnTransition(
(styles, selected) =>
selected && (
<animated.div style={styles}>
<CreateOcoOrdersButton onClick={onCreateOcoOrders} />
</animated.div>
),
)}
{/* withCloseBtn && <CloseOrderButton onClick={onCloseHandler} /> removed close Button */}
</OrderContainerInnerStyled>
</OrderContainerStyled>
);
};
export const OverridingOrderComponent = () => {
const onApiCreated = (api: ChartReactAPI) => {
api.onChartCreated((_chartId, _chartInstance) => {});
};
const chartReactAppContainerProps = { width: 800, height: 50 };

return (
<>
<ChartReactAppContainer {...chartReactAppContainerProps}>
<div className={'chart-react-container'} />
</ChartReactAppContainer>
<FlexContainer justifyContent={'flex-start'}>
<ChartReactAppWrapper
customConfig={{
trading: {
enabled: true,
},
}}
dependencies={{ ...CREATE_MOCK_PROVIDERS(), onApiCreated }}
uiOverrides={{
trading: {
RegularOrder,
},
}}
/>
</FlexContainer>
</>
);
};
Order component without close button

Source code

import React, { MouseEvent, useCallback, useContext, useMemo, useRef } from 'react';
import { ChartReactAppContainer, ChartReactAppWrapper } from '../../../../../src/components/ChartReactApp';
import { FlexContainer } from '../../../../../src/components/FlexContainer';
import { OverrideProps } from '@dx-private/dxchart5-react/dist/chart/ui-overrides';
import { CREATE_MOCK_PROVIDERS } from '@dx-private/dxchart5-react-mock-providers';
import { ChartReactAPI } from '@dx-private/dxchart5-react/dist/chart/view-models/api/chart-react-api.view-model';
import { OrderProps } from '@dx-private/dxchart5-react/dist/chart/components/trading/order/components/order.component';
import { animated, useTransition } from '@react-spring/web';
import {
CreateOcoOrdersButton,
useOcoButtonsTransition,
} from '@dx-private/dxchart5-react/dist/chart/components/trading/order/components/create-oco-orders-button.component';
import {
getRegularOrderName,
isSelectSkippable,
renderSLTPShortcutSection,
skipSelectOrder,
} from '@dx-private/dxchart5-react/dist/chart/components/trading/order/order.functions';
import {
OrderContainerInnerStyled,
OrderContainerStyled,
OrderDelimiterStyled,
OrderSectionStyled,
} from '@dx-private/dxchart5-react/dist/chart/components/trading/order/components/order.styled';
import { DeselectOrderButton } from '@dx-private/dxchart5-react/dist/chart/components/trading/order/components/deselect-order-button.component';
import { Side } from '@dx-private/dxchart5-react/dist/chart/components/trading/order/components/side.component';
import { RegularOrderProps } from '@dx-private/dxchart5-react/dist/chart/components/trading/order/regular-order.component';
import {
checkOrderIsOnUIOnly,
getOrderPriceByType,
isProtection,
} from '@dx-private/dxchart5-react/dist/chart/model/trading/trading.model';
import {
AddSLOrderBtnStyled,
AddTPOrderBtnStyled,
OrderSLTPShortcutSectionStyled,
} from '@dx-private/dxchart5-react/dist/chart/components/trading/order/regular-order.styled';
import { TEST_IDS } from '@dx-private/dxchart5-react/dist/config/e2e/test-ids';
import { defaultOrderPriceFormatter } from '@dx-private/dxchart5-react/dist/chart/model/trading/order.model';
import { OrderLineStyled } from '@dx-private/dxchart5-react/dist/chart/components/trading/order/components/side.styled';
import { MultiChartComponentContext } from '@dx-private/dxchart5-react/dist/chart/components/multi-chart/multi-chart-context';
const OrderComponent = (props: OrderProps) => {
const {
children,
absoluteChildren,
side,
selected = false,
disabled = false,
className,
testId,
onClick,
onSelect,
onDblClick,
onDeselect,
withDeselectBtn = false,
data = {},
canCreateOCO = false,
onCreateOcoOrders,
} = props;
const timeoutId: React.MutableRefObject<number | null> = useRef(null);
const deselectBtnTransition = useTransition(selected && withDeselectBtn, {
config: {
duration: 150,
},
from: { position: 'absolute' as const, y: 0, x: 0, zIndex: -1, opacity: 0 },
enter: { x: -20, opacity: 1 },
leave: { x: 0, opacity: 0 },
delay: 150,
});
const ocoBtnTransition = useOcoButtonsTransition(selected && canCreateOCO);
const onDeselectHandler = useCallback(
(e: React.MouseEvent) => {
e.stopPropagation();
if (onDeselect) {
onDeselect();
}
},
[onDeselect],
);
const onClickHandler = useCallback(
(e: React.MouseEvent<HTMLDivElement, MouseEvent & DragEvent>) => {
e.stopPropagation();
timeoutId?.current && clearTimeout(timeoutId.current);
if (onClick && e.detail === 1) {
timeoutId.current = setTimeout(onClick, 200);
} else if (onDblClick && e.detail === 2) {
onDblClick();
}
if (onSelect && !isSelectSkippable(e)) {
onSelect();
} else {
skipSelectOrder(e, false);
}
},
[onSelect, onClick, onDblClick],
);
const dataAttrs = useMemo(
() => Object.entries(data).reduce((acc, [k, v]) => ({ ...acc, [`data-${k}`]: v }), {}),
[data],
);
return (
<OrderContainerStyled {...dataAttrs} className={className} disabled={disabled} data-test-id={testId}>
{withDeselectBtn &&
deselectBtnTransition(
(styles, selected) =>
selected && (
<animated.div style={styles}>
<DeselectOrderButton onClick={onDeselectHandler} />
</animated.div>
),
)}
{absoluteChildren}
<OrderContainerInnerStyled onClick={onClickHandler} disabled={disabled} selected={selected}>
<Side side={side} />
{children}
{canCreateOCO &&
ocoBtnTransition(
(styles, selected) =>
selected && (
<animated.div style={styles}>
<CreateOcoOrdersButton onClick={onCreateOcoOrders} />
</animated.div>
),
)}
{/* withCloseBtn && <CloseOrderButton onClick={onCloseHandler} /> removed close Button */}
</OrderContainerInnerStyled>
</OrderContainerStyled>
);
};
export const RegularOrder = ({
chartReactAPIProps: _chartApi,
originalProps: props,
}: OverrideProps<RegularOrderProps>) => {
const {
order,
createProtectionOrder,
takeProfitStopLossEnabled,
showPriceAsLabels,
onClose,
onDeselect,
onSelect,
onClick,
onDblClick,
isLineVisible = true,
horizontalLineWidth,
onCreateOcoOrders,
} = props;
const { localization } = useContext(MultiChartComponentContext);
const { disabled, selected, model, marketPrice } = order;
const { id, side, quantity, orderType, limitPrice, stopPrice } = model;
const [isSLLinked, isTPLinked] =
!isProtection(order.model) && order.model.protectionOrderIds
? order.model.protectionOrderIds.map(id => !!id && !checkOrderIsOnUIOnly(id))
: ([false, false] as const);
const [showSLBtn, showTPBtn] =
!isProtection(order.model) && order.model.protectionOrderIds
? order.model.protectionOrderIds.map(id => Boolean(id))
: [false, false];
const onSelectHandler = useCallback(() => onSelect && !selected && onSelect(id), [id, onSelect, selected]);
const onClickHandler = useCallback(() => onClick && onClick(id), [id, onClick]);
const onDblClickHandler = useCallback(() => onDblClick && onDblClick(id), [id, onDblClick]);
const onDeselectHandler = useCallback(() => onDeselect && onDeselect(id), [id, onDeselect]);
const onCloseHandler = useCallback(() => onClose && onClose(id), [id, onClose]);
const addTPOrderHandler = useCallback(
(e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>) => {
e.stopPropagation();
createProtectionOrder && createProtectionOrder('tp', id);
},
[createProtectionOrder, id],
);
const addSLOrderHandler = useCallback(
(e: MouseEvent<HTMLButtonElement, globalThis.MouseEvent>) => {
e.stopPropagation();
createProtectionOrder && createProtectionOrder('sl', id);
},
[createProtectionOrder, id],
);
const tpTransition = useTransition(selected && !showTPBtn, {
config: {
duration: 150,
},
from: { position: 'absolute' as const, y: 0, top: 0, left: '50%', zIndex: -1, x: '-50%', opacity: 0 },
enter: {
y: side === 'buy' ? -20 : 20,
opacity: 1,
},
leave: showTPBtn ? { opacity: 0 } : { y: 0, opacity: 0 },
});
const slTransition = useTransition(selected && !showSLBtn, {
config: {
duration: 150,
},
from: { position: 'absolute' as const, y: 0, top: 0, left: '50%', zIndex: -1, x: '-50%', opacity: 0 },
enter: {
y: side === 'buy' ? 20 : -20,
opacity: 1,
},
leave: showSLBtn ? { opacity: 0 } : { y: 0, opacity: 0 },
});
const renderSLTPButtons = useMemo(() => {
return (
<>
{tpTransition(
(styles, show) =>
show && (
<animated.div style={styles}>
<AddTPOrderBtnStyled onClick={addTPOrderHandler}>
{localization.trading.protectionOrders.addButtons.takeProfit}
</AddTPOrderBtnStyled>
</animated.div>
),
)}
{slTransition(
(styles, show) =>
show && (
<animated.div style={styles}>
<AddSLOrderBtnStyled onClick={addSLOrderHandler}>
{localization.trading.protectionOrders.addButtons.stopLoss}
</AddSLOrderBtnStyled>
</animated.div>
),
)}
</>
);
}, [
tpTransition,
slTransition,
addTPOrderHandler,
addSLOrderHandler,
localization.trading.protectionOrders.addButtons.stopLoss,
localization.trading.protectionOrders.addButtons.takeProfit,
]);
const price = getOrderPriceByType(orderType, limitPrice, stopPrice, marketPrice);
return (
<>
<OrderComponent
data={order.model.data}
canCreateOCO={order.model.canCreateOCO}
side={side}
disabled={disabled}
selected={selected}
testId={`${TEST_IDS.order_item}_${id}`}
onSelect={onSelectHandler}
onClick={onClickHandler}
onDblClick={onDblClickHandler}
onClose={onCloseHandler}
onDeselect={onDeselectHandler}
absoluteChildren={takeProfitStopLossEnabled && renderSLTPButtons}
onCreateOcoOrders={onCreateOcoOrders}
withDeselectBtn>
<OrderSectionStyled>{quantity}</OrderSectionStyled>
<OrderDelimiterStyled margin="both" />
<OrderSectionStyled>{`${getRegularOrderName(orderType, localization.trading)} ${
!showPriceAsLabels ? (order.formatter || defaultOrderPriceFormatter)(price) : ''
}`}</OrderSectionStyled>
{(isSLLinked || isTPLinked) && (
<>
<OrderDelimiterStyled margin="both" />
<OrderSLTPShortcutSectionStyled>
{renderSLTPShortcutSection(isSLLinked, isTPLinked)}
</OrderSLTPShortcutSectionStyled>
<OrderDelimiterStyled margin="both" />
</>
)}
</OrderComponent>
{isLineVisible && (
<OrderLineStyled
x={'101%'}
y={9.5}
width={horizontalLineWidth}
disabled={disabled}
selected={selected}
/>
)}
</>
);
};
export const OverridingOrderComponent = () => {
const onApiCreated = (api: ChartReactAPI) => {
api.onChartCreated((_chartId, _chartInstance) => {});
};
const chartReactAppContainerProps = { width: 800, height: 50 };
return (
<>
<ChartReactAppContainer {...chartReactAppContainerProps}>
<div className={'chart-react-container'} />
</ChartReactAppContainer>
<FlexContainer justifyContent={'flex-start'}>
<ChartReactAppWrapper
customConfig={{
trading: {
enabled: true,
},
}}
dependencies={{ ...CREATE_MOCK_PROVIDERS(), onApiCreated }}
uiOverrides={{
trading: {
RegularOrder,
},
}}
/>
</FlexContainer>
</>
);
};

Position integration and overriding

Observing positions

The observePositions callback is scoped per instrument (symbol).

Each symbol has its own subscription and position mapping. The user receives only the updates about the symbol which they are subscribed to.

Unsubscribing

To avoid memory leaks, always unsubscribe when switching symbols or switching off components.

Subscriptions are tied to the lifecycle of the chart or instrument view, especially in dynamic setups.

Overriding the Position widget

Similarly to the Order component, you can override the Position widget using uiOverrides.trading.

  • Supported starting from version 5.13.5.

  • If the widget fails to render or respond, make sure you're using v5.13.5 or later.

For additional guidance or sample setups, contact DXcharts Support.