Библиотека Choices.js предоставляет слой над стандартными
<select> и <input> элементами,
превращая их в управляемые интерфейсные компоненты с поддержкой поиска,
тегов и кастомного отображения данных. Отображение значений в интерфейсе
не ограничивается строковым выводом: каждый элемент проходит через
систему шаблонов и рендер-функций, позволяющих формировать представление
данных любой сложности, включая числа и даты.
Внутренне Choices.js оперирует объектами Choice и
Item, где ключевыми полями выступают:
label — отображаемый текстvalue — значение, используемое в формеcustomProperties — дополнительные данные для
расширенного рендерингаФорматирование чисел и дат обычно реализуется не на уровне самой библиотеки, а через подготовку данных или кастомные шаблоны отображения.
Числовые значения в Choices.js часто используются в сценариях фильтрации: цены, рейтинги, количества, диапазоны. На уровне данных целесообразно хранить «сырое» значение отдельно от отображаемого.
Типовая структура:
const choicesData = [
{
value: 'plan_basic',
label: 'Базовый тариф',
customProperties: {
price: 4900
}
},
{
value: 'plan_pro',
label: 'Профессиональный тариф',
customProperties: {
price: 12900
}
}
];
Такой подход позволяет отделить бизнес-данные от визуального представления, оставляя форматирование на стороне UI-слоя.
Для локализованного отображения чисел используется стандартный API
Intl.NumberFormat. Он обеспечивает корректное
форматирование валют, разделителей тысяч и десятичных знаков.
Пример форматирования цены:
const priceFormatter = new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency: 'RUB',
minimumFractionDigits: 0
});
Функция отображения значения внутри Choices.js:
const formatChoiceLabel = (label, customProperties) => {
const price = customProperties?.price;
if (typeof price === 'number') {
return `${label} — ${priceFormatter.format(price)}`;
}
return label;
};
Choices.js позволяет переопределять шаблоны через
callbackOnCreateTemplates, где задаются функции
формирования DOM-структур для элементов списка и выбранных значений.
Пример интеграции форматирования чисел:
const choices = new Choices('#select', {
shouldSort: false,
callbackOnCreateTemplates: function (template) {
return {
item: (classNames, data) => {
const price = data.customProperties?.price;
const label = price !== undefined
? `${data.label} — ${priceFormatter.format(price)}`
: data.label;
return template(`
<div class="${classNames.item} ${data.highlighted
? classNames.highlightedState
: classNames.itemSelectable}"
data-item
data-id="${data.id}"
data-value="${data.value}">
${label}
</div>
`);
}
};
}
});
Такой механизм обеспечивает полный контроль над тем, как отображаются числовые данные в списках выбора и выбранных элементах.
В некоторых интерфейсах Choices.js используется отображение диапазонов цен или агрегированных чисел.
Пример подготовки данных:
{
value: 'range_1',
label: 'Эконом',
customProperties: {
min: 1000,
max: 5000
}
}
Формирование отображения:
const formatRange = (min, max) => {
return `${priceFormatter.format(min)} – ${priceFormatter.format(max)}`;
};
Использование в шаблоне:
const label = `${data.label} (${formatRange(min, max)})`;
Подобный подход часто применяется в фильтрах интернет-магазинов и аналитических интерфейсах.
Работа с датами требует аналогичного разделения данных и отображения.
Внутри customProperties обычно хранится ISO-строка или
timestamp.
Пример структуры:
{
value: 'event_1',
label: 'Запуск продукта',
customProperties: {
date: '2026-05-23T10:00:00Z'
}
}
Для форматирования дат применяется Intl.DateTimeFormat,
обеспечивающий локализацию отображения.
const dateFormatter = new Intl.DateTimeFormat('ru-RU', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
Функция преобразования:
const formatDate = (isoString) => {
const date = new Date(isoString);
if (Number.isNaN(date.getTime())) {
return '';
}
return dateFormatter.format(date);
};
Интеграция с шаблоном:
const choices = new Choices('#events', {
callbackOnCreateTemplates: (template) => ({
item: (classNames, data) => {
const date = data.customProperties?.date;
const formattedDate = date ? formatDate(date) : '';
return template(`
<div class="${classNames.item} ${classNames.itemSelectable}"
data-item
data-id="${data.id}"
data-value="${data.value}">
<span>${data.label}</span>
${formattedDate ? `<small>${formattedDate}</small>` : ''}
</div>
`);
}
})
});
Такой подход позволяет визуально отделять основное название события от временной метки.
В сложных интерфейсах один элемент может содержать одновременно числовые и временные данные, например финансовые транзакции.
Структура данных:
{
value: 'tx_1',
label: 'Оплата заказа',
customProperties: {
amount: 2590,
date: '2026-05-23T08:30:00Z'
}
}
Формирование отображения:
const formatTransaction = (data) => {
const amount = data.customProperties?.amount;
const date = data.customProperties?.date;
const formattedAmount = typeof amount === 'number'
? priceFormatter.format(amount)
: '';
const formattedDate = date ? formatDate(date) : '';
return `
${data.label}
<span class="meta">
${formattedAmount}
${formattedDate}
</span>
`;
};
Форматирование чисел и дат в Choices.js тесно связано с локализацией
интерфейса. Использование Intl позволяет избежать жестко
заданных форматов и адаптировать представление под разные языки и
регионы.
Основные аспекты:
При смене языка интерфейса достаточно пересоздать форматтеры:
const createFormatters = (locale) => ({
number: new Intl.NumberFormat(locale),
currency: new Intl.NumberFormat(locale, { style: 'currency', currency: 'USD' }),
date: new Intl.DateTimeFormat(locale)
});
При форматировании данных внутри Choices.js важно учитывать некорректные или неполные значения.
Типовые ситуации:
null или undefined в
customPropertiesInvalid Date)Защитная обработка:
const safeNumberFormat = (value) => {
if (typeof value !== 'number' || Number.isNaN(value)) {
return '';
}
return priceFormatter.format(value);
};
const safeDateFormat = (value) => {
const date = new Date(value);
if (Number.isNaN(date.getTime())) {
return '';
}
return dateFormatter.format(date);
};
При большом количестве элементов Choices.js (сотни или тысячи значений) повторное создание форматтеров или вычислений внутри рендер-функций приводит к деградации производительности.
Оптимизационные практики:
Intl.NumberFormat и
Intl.DateTimeFormat один разcallbackOnCreateTemplatesПример предварительной подготовки:
const preparedData = rawData.map(item => ({
...item,
displayLabel: `${item.label} — ${priceFormatter.format(item.customProperties.price)}`,
displayDate: formatDate(item.customProperties.date)
}));
В архитектурно устойчивых решениях Choices.js используется принцип разделения:
value — идентификаторlabel — базовое имяcustomProperties — сырые данныеdisplay* — предрасчитанные строки для UIТакое разделение снижает связанность UI-логики с бизнес-данными и упрощает поддержку сложных форматов чисел и дат.
Форматирование часто дополняется стилизацией:
.choices__item small {
display: block;
opacity: 0.7;
font-size: 12px;
}
.choices__item .meta {
display: flex;
gap: 8px;
font-size: 12px;
}
CSS завершает визуальную структуру, сформированную JavaScript-слоем форматирования.