The useInputCurrency hook manages the complex state and behavior of currency input fields, automatically switching between numeric and formatted display modes, and providing style variables for currency symbols.
Import
import { useInputCurrency } from '@dynamic-framework/ui-react';
Signature
function useInputCurrency(
currencyOptions: Options,
value?: number,
onFocus?: (event: FocusEvent<HTMLInputElement>) => void,
onChange?: (value?: number) => void,
onBlur?: (event: FocusEvent<HTMLInputElement>) => void,
ref?: ForwardedRef<HTMLInputElement>,
): UseInputCurrencyReturn
Parameters
Currency.js options object for formatting. See currency.js documentation for all available options.type Options = {
symbol?: string;
separator?: string;
decimal?: string;
precision?: number;
// ... other currency.js options
}
The current numeric value of the input. Can be undefined for empty inputs.
onFocus
(event: FocusEvent<HTMLInputElement>) => void
Callback fired when the input receives focus. The hook’s internal handler will be called first.
Callback fired when the input value changes. Receives the numeric value or undefined if empty.
onBlur
(event: FocusEvent<HTMLInputElement>) => void
Callback fired when the input loses focus. The hook’s internal handler will be called first.
ref
ForwardedRef<HTMLInputElement>
Optional React ref to forward to the input element. If not provided, the hook creates one internally.
Return Value
type UseInputCurrencyReturn = {
inputRef: RefObject<HTMLInputElement>;
innerValue: string;
innerType: string;
handleOnFocus: (event: FocusEvent<HTMLInputElement>) => void;
handleOnChange: (value?: string) => void;
handleOnBlur: (event: FocusEvent<HTMLInputElement>) => void;
generateStyleVariables: CustomStyles;
generateSymbolStyleVariables: CSSProperties;
}
inputRef
RefObject<HTMLInputElement>
Ref object to attach to the input element
The current display value for the input (formatted when blurred, raw number when focused)
The current input type: "number" when focused, "text" when blurred
Focus event handler that switches to numeric input mode
Change event handler that updates the value and calls the provided onChange callback
Blur event handler that switches to formatted text display mode
CSS custom properties for styling the input component:{
'--d-input-currency-component-symbol-color': 'var(--d-secondary)',
'--d-input-currency-symbol-color': 'var(--d-input-currency-component-symbol-color)'
}
generateSymbolStyleVariables
Style object for the currency symbol element:{
color: 'var(--d-input-currency-symbol-color)'
}
Usage
import { useInputCurrency } from '@dynamic-framework/ui-react';
function CurrencyInput({ value, onChange }) {
const currencyOptions = {
symbol: '$',
separator: ',',
decimal: '.',
precision: 2
};
const {
inputRef,
innerValue,
innerType,
handleOnFocus,
handleOnChange,
handleOnBlur,
generateStyleVariables,
generateSymbolStyleVariables
} = useInputCurrency(
currencyOptions,
value,
undefined,
onChange
);
return (
<div style={generateStyleVariables}>
<span style={generateSymbolStyleVariables}>
{currencyOptions.symbol}
</span>
<input
ref={inputRef}
type={innerType}
value={innerValue}
onFocus={handleOnFocus}
onChange={(e) => handleOnChange(e.target.value)}
onBlur={handleOnBlur}
/>
</div>
);
}
With Custom Callbacks
import { useInputCurrency } from '@dynamic-framework/ui-react';
import { useState } from 'react';
function PriceInput() {
const [price, setPrice] = useState<number | undefined>(0);
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
console.log('Input focused');
};
const handleChange = (value?: number) => {
setPrice(value);
console.log('New price:', value);
};
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
console.log('Input blurred with value:', price);
};
const {
inputRef,
innerValue,
innerType,
handleOnFocus,
handleOnChange,
handleOnBlur
} = useInputCurrency(
{ symbol: '$', precision: 2, separator: ',', decimal: '.' },
price,
handleFocus,
handleChange,
handleBlur
);
return (
<input
ref={inputRef}
type={innerType}
value={innerValue}
onFocus={handleOnFocus}
onChange={(e) => handleOnChange(e.target.value)}
onBlur={handleOnBlur}
/>
);
}
Forwarding Ref
import { useInputCurrency } from '@dynamic-framework/ui-react';
import { useRef, forwardRef } from 'react';
const CurrencyInput = forwardRef<HTMLInputElement, Props>(
({ value, onChange }, ref) => {
const {
inputRef,
innerValue,
innerType,
handleOnFocus,
handleOnChange,
handleOnBlur
} = useInputCurrency(
{ symbol: '$', precision: 2, separator: ',', decimal: '.' },
value,
undefined,
onChange,
undefined,
ref
);
return (
<input
ref={inputRef}
type={innerType}
value={innerValue}
onFocus={handleOnFocus}
onChange={(e) => handleOnChange(e.target.value)}
onBlur={handleOnBlur}
/>
);
}
);
Complete Styled Component
import { useInputCurrency } from '@dynamic-framework/ui-react';
import styled from 'styled-components';
const InputWrapper = styled.div`
display: flex;
align-items: center;
border: 1px solid #ccc;
padding: 8px 12px;
border-radius: 4px;
&:focus-within {
border-color: #007bff;
}
`;
const Symbol = styled.span`
margin-right: 4px;
font-weight: 600;
`;
const Input = styled.input`
border: none;
outline: none;
flex: 1;
font-size: 16px;
`;
function StyledCurrencyInput({ value, onChange }) {
const {
inputRef,
innerValue,
innerType,
handleOnFocus,
handleOnChange,
handleOnBlur,
generateStyleVariables,
generateSymbolStyleVariables
} = useInputCurrency(
{ symbol: '$', precision: 2, separator: ',', decimal: '.' },
value,
undefined,
onChange
);
return (
<InputWrapper style={generateStyleVariables}>
<Symbol style={generateSymbolStyleVariables}>$</Symbol>
<Input
ref={inputRef}
type={innerType}
value={innerValue}
onFocus={handleOnFocus}
onChange={(e) => handleOnChange(e.target.value)}
onBlur={handleOnBlur}
/>
</InputWrapper>
);
}
Behavior
The hook automatically switches between two modes:
- Focused (Number Mode): When the input has focus, it displays the raw numeric value and sets
type="number" for easier editing
- Blurred (Text Mode): When focus is lost, it displays the fully formatted currency string with symbol, separators, and precision
Value Synchronization
The hook synchronizes external value prop changes with internal state, ensuring the displayed value updates when the parent component changes the value.
Event Handling
All event handlers (focus, change, blur) call event.stopPropagation() to prevent event bubbling, which can be important in complex form layouts.
Implementation Details
- Uses
useProvidedRefOrCreate to handle optional ref forwarding
- Manages internal state for display value, numeric value, and input type
- Formats values using the
currency.js library
- Provides CSS custom properties for consistent theming
- Memoizes style objects and callbacks for performance