# Override product module styling
Override UI elements of product modules in the InStore POS to match brand, workflow, and localization requirements.
Product modules in `modular_store` share a default UI theme that is configured in the InStore Center on the **Theme** tab of the environment.
You can override the theme and other presentation aspects for the following product modules that run inside the InStore POS:
- `InStore_Payment`
- `InStore_Refund`
- `InStore_DeviceManagement`
- `InStore_CashManagement`
You must call the relevant API before these modules are called. You can override the following:
- [Theme](/instore/customization/product-module-styling-overrides.md#override-theme)
- [Strings](/instore/customization/product-module-styling-overrides.md#override-strings)
- [Print options](/instore/customization/product-module-styling-overrides.md#override-print-options)
- [Payment Totals box](/instore/customization/product-module-styling-overrides.md#add-payment-details-to-the-totals-box)
## Override theme
Product modules adopt the colors defined on the **Theme** tab in the InStore Center unless you explicitly override them. To override the theme, follow these steps:
1. Import the `useStore` hook from [`InStore_State`](https://github.com/NebulaTerra/modular-store/tree/main/InStore_State).
2. Access `configuration` from `useStore` in your top-level layout (for example, `InStore_Shell/src/views/layout.tsx`).
3. Call `configuration.setOverrideCoreTheme(true)` before any product module mounts.
4. Provide custom `themeOptions` through the theme provider (for example, `InStore_Shell/src/providers/theme.tsx`).
```tsx title="Import store hook"
import { useStore } from "InStore_State/store";
```
```tsx title="Access configuration"
const Layout = () => {
const { configuration } = useStore();
// ...
};
```
```tsx title="Enable core theme override"
useEffect(() => {
configuration.setOverrideCoreTheme(true);
}, []);
```
```tsx title="Provide custom theme"
import React, { PropsWithChildren } from 'react';
import { ThemeProvider as TP } from 'InStore_State/theme';
import customTheme from '../theme/customTheme';
const ThemeProvider = ({ children }: PropsWithChildren) => (
{children}
);
```
Front-end modules use Tailwind. Product modules use the 12‑column Grid (v1) version of [Material UI (MUI) 5](https://v5.mui.com/material-ui/react-grid/), specifically:
- MUI base v. 5.0.0-beta.34
- MUI icons-material v. 5.8.0
- MUI material v. 5.8.1
- MUI system v. 5.15.0
The following examples show how to configure the elements' size and color, but not the text.
The action button bar background color is not part of Material UI. Set it with the **Base Background** control on the **Environment** > **Theme** tab in the InStore Center.
### Payment types structure
```tsx title="Payment types layout"
```

### Cash structure
```tsx title="Cash layout"
```

### Cash drawer structure
```tsx title="Cash drawer layout"
```

### Change due structure
```tsx title="Change due layout"
```

### Credit processing structure
```tsx title="Credit processing layout"
```

### Stored-value card entry structure
```tsx title="Stored-value card entry layout"
```

### HTML structures for Pay On Account
Use this wrapper to introduce the POA component:
```
```
### HTML structure for POA Company Name label and field
```
<>
{t('POA.companyName')}
{customer.company}
>
```
### HTML structure for POA Authorized Purchaser label and field
```
<>
{t('POA.authorizedPurchaser')}
{customer.first_name + ' ' + customer.last_name}
>
```
### HTML structure for POA Customer Number label and field
```
<>
{t('POA.customerNumber')}
{customer.customer_number}
>
```
### HTML structure for POA Customer Email label and field
```
<>
{t('POA.customerEmail')}
{customer.email}
>
```
### HTML structure for POA Account IDs label and drop-down
```
<>
{t('POA.accountID')}
{accountNumber}
>
```
### HTML structure for POA page divider
```
```
### HTML structure for POA Payment Amount label and field
```
<>
{t('POA.paymentAmount')}
{currentTenderAmount.toFormat(currencyInstance.currencyFormat)}
>
```
### HTML structure for POA Purchase Order label and field
```
<>
{t('POA.purchaseOrderLabel')}
>
```
### HTML structure for POA navigation buttons
```
```
### Pay On Account HTML rendered on the UI

### Override strings
For core product functions, InStore retrieves UI strings from the InStore API. For [modifiable modules](/instore/implement-instore/modules/working-with-instore-modules.md), the API is consulted first and the predefined language bundles second. Override only the keys you want to change. Other keys fall back to defaults.
Follow these steps to override strings:
1. Specify overrides as shown in [this example](/instore/customization/product-module-styling-overrides.md#example). If you have multiple languages, add a section for each language as shown.
2. Define a payload `{ ... }` for each section based on the main payload in the example. The payload only needs to include the strings to be overridden, you don't need to include strings in the payload if you don't want to override them.
3. Get an administrator access token. The credentials used here are the same as the ones you use with all InStore APIs.
4. Send a PUT request to `/:tenantId/translations`, and then send the payload. You must include `{{login_token}}` in the header of your request. For example, in the [PUT](/instore/customization/product-module-styling-overrides.md#route) call, insert the `{{login_token}}` as the value for the token key that pairs with the header.
5. The returned response is the updated bundle in JSON format.
### Route
| Path | Type | Description |
| --- | --- | --- |
| /:tenantId/translations | PUT | Override default translations for supported locales. |
### Request
| Field | Type | Description |
| --- | --- | --- |
| `translations` | array | List of per-locale translation override objects. |
### Example
```json title="Tender label overrides"
{
"translations": [
{
"locale": "en-US",
"bundle": {
"Checkout": {
"buttons": {
"cash": "CASH",
"typeCards": "CREDIT / DEBIT",
"giftCard": "GIFT CARD",
"digitalWallet": "DIGITAL WALLET",
"poa": "PAY-ON-ACCOUNT",
"payByLink": "PAY BY LINK"
}
}
}
}
]
}
```
### Override tender order and icons
1. Log in to the InStore API server with administrator credentials and obtain a token.
2. Add the token to the request header.
3. Send `PUT /:tenantId/payment-buttons` with a payload describing order and icons.
4. A successful update returns status code `202` and the updated configuration.
### Route
| Path | Type | Description |
| --- | --- | --- |
| /:tenantId/payment-buttons | PUT | Update tender display configuration and return the tenant document. |
### Request fields
| Field | Type | Description | Example |
| --- | --- | --- | --- |
| `paymentButtons` | array | Array of button configuration objects. | See example |
| `paymentButtons[].key` | string | Identifier of the payment button to update. | `creditCard` |
| `paymentButtons[].icon` | string | Material UI icon component name. | `CreditCard` |
| `paymentButtons[].order` | integer | Display order (1–10). | 1 |
### Example
```json title="Tender order and icon overrides"
{
"paymentButtons": [
{ "key": "creditCard", "icon": "CreditCard", "order": 1 },
{ "key": "cash", "icon": "Money1", "order": 2 }
]
}
```
To optimize performance, InStore loads only a subset of Material UI icons. If you want to use an icon that is not included in the preloaded set, contact the [InStore support team](https://commercetools.atlassian.net/servicedesk/customer/portal/22).
### Example
The following example replaces the string `Cash Drawer` with `Till` in the `en-GB` bundle.
```json title="Translations override payload (excerpt)"
{
"translations": [
{
"locale": "en-GB",
"bundle": {
"CashCollection": {
"promptMessage": "Select or enter cash Remaining Balance.",
"promptMessageChangeDue": "Please give Change Due to customer and close the till.",
"userMessageCreditApproved": "Card payment approved."
},
"CashDrawer": {
"promptMessageClose": "Confirm the till is closed and press OK.",
"promptMessageSelection": "Select the Till and Reason for the count.",
"promptMessagePayInOpen": "Place cash received in drawer, close the drawer, and press DONE.",
"promptMessagePayOutOpen": "Remove disbursement amount from drawer, close the drawer, and press DONE.",
"promptMessageCashAuditOpen": "Remove transfer amount from drawer, close the drawer, and press DONE.",
"userMessageOpenCashDrawer": "Till open.",
"userMessageCashDrawerClosed": "Till closed."
},
"CashManagement": {
"promptMessageMenu": "Please Select a cash management process.",
"promptMessagePayIn": "Enter the Amount Received and select a Reason.",
"promptMessagePayOut": "Enter the disbursement amount and select a reason.",
"promptMessageCashCount": "Enter the Count for each currency denomination.",
"promptMessageCashCountSummary": "Enter the total counted cash.",
"promptMessageCountAcceptance": "Choose to ACCEPT Count or RECOUNT.",
"promptMessageCashAudit": "Select a Till, review the data and press DONE to finish.",
"promptMessageSafeDeposit": "Select the Till and Reason and press NEXT to continue.",
"promptMessageSafeReserve": "Leave the Reserve Amount in the drawer. Close the drawer. Place the Deposit Amount in the safe, and press DONE.",
"promptMessageBankDepositReserve": "Leave the Reserve Amount in the safe. Send the deposit amount to the bank, and press DONE."
}
}
}
]
}
```
You can override strings for modifiable modules by accessing your local copy of the InStore Client `translation.json` file for the language that is in use. You can obtain a language bundle with relevant keys from commercetools.
Note that any overrides present in the API take precedence over bundle overrides.
### Override print options
You can override print options from any [module](/instore/implement-instore/modules/working-with-instore-modules.md) in `modular_store`. For example, you can omit a receipt option on the cart if certain conditions on the customer record are not met.
1. Import `useStore` from `InStore_State/store`.
2. Access `configuration` from `useStore`.
3. Call `configuration.setOverridePrintOptions([...])` to set allowed print options for Checkout or Refund in the `InStore_Core` module.
```tsx title="Override print options"
import { useStore } from 'InStore_State/store';
```
4. Call `setOverridePrintOptions` in any part of the component to override print options on Checkout or Refund in the InStore core application.
```
configuration.setOverridePrintOptions(['Paper']);
//Options: Paper, Email, Text, and None
```
Make sure that the value of `setOverridePrintOptions` is either an array of strings or `null`. If this override consists of `null`, then InStore uses the values that were set by the [Receipt\_Print\_Options](/instore/customization/administration-parameters.md#print-parameters) administration parameter in the InStore Center.
An array will replace the values that were configured by the administration parameter.
For more information, see how to set an [event type](/instore/implement-instore/integrate-with-instore/events.md#instorecore-receiptchoice) for capturing the choice of receipt.
## Add payment details to the Totals box
You can add your own specific information to display to your colleagues at the top of the **Totals** box during checkout. For example, you can display loyalty benefits, customer entitlements, or applied discount information to help the colleague to explain the amount due for a customer.
The additional information is added within a flexibly sized component called the `MoneyBoxInjection`. You can call the InStore `moneyBoxInjection` property at render time.
To display payment details within the **Totals** box, do the following:
1. Follow the steps [for overriding the theme](/instore/customization/product-module-styling-overrides.md#override-theme) and add the following to the `configuration`:
```
Injector.inject({
tenantId: "a1a1-b2b2-c3c3-d4d4",
moneyBoxInjection: {
items: [
{ label: "Shopper due 1000 Loyalty points on checkout", alignment: "center" },
{ type: "divider" },
{ label: "Stored value available to use: £180.50", alignment: "right" },
{ type: "divider" },
{ label: "Price Match Applied:", value: "-£10.00", alignment: "left" },
]
}
});
```
2. For each item in the `items` array, assign one of the following options:
```
{
"label": "Promo: Buy 1 Get 1 Free!",
"value": "-£1.00",
"alignment": "center"
}
```
3. Implement a divider (a horizontal line) by inserting the following text:
```
{ "type": "divider" }
```
Use theming described elsewhere in this topic to style line thickness, color, and spacing.
4. Use theming overrides to style the `MoneyBoxInjection` component. For example:
```
MoneyBoxInjection: {
styleOverrides: {
root: {
"&.instore-moneybox-injection": {
textAlign: themeOptions.defaultTextAlign || "left",
margin: themeOptions.moneyBoxMargin || "4px 0",
fontSize: themeOptions.moneyBoxFontSize || "14px",
color: themeOptions.moneyBoxTextColor || "#000",
"& .instore-moneybox-item-left": { textAlign: "left" },
"& .instore-moneybox-item-center": { textAlign: "center" },
"& .instore-moneybox-item-right": { textAlign: "right" },
"& .instore-moneybox-separator": {
borderTop: `1px solid ${themeOptions.moneyBoxSeparatorColor || "rgba(0,0,0,0.3)"}`,
margin: themeOptions.moneyBoxSeparatorSpacing || "4px 0",
},
}
}
}
}
```
## Related pages
- [Area overview page with navigation](/instore.md)
- [Previous page: Implement features using administration parameters](/instore/customization/parameter-based-features.md)
- [Next page: Customize payment stepper messages](/instore/customization/payment-stepper-customization.md)
- [Search documentation and API specs](/search.md)