Skip to main content

Custom Fields

Custom fields provide a flexible extension mechanism for attaching additional data to product options beyond standard properties. They enable you to store product-specific information, technical specifications, vendor codes, or any custom data needed for your business logic.

What Are Custom Fields Used For?

Custom fields are primarily used in system-level operations configured through the admin panel:

  • SKU Generation - Include custom data in product codes (e.g., K-ST{size#vendorCode}/{wood#thickness})
  • Pricing Rules - Base pricing calculations on custom attributes
  • BOM (Bill of Materials) - Track manufacturing specifications
  • Business Rules - Control visibility of meshes, components, or 2D layers based on custom values
  • Variables - Store data used in formulas and calculations

While these operations are configured in the admin panel, custom fields become important when building custom UI because you may need to display this data, use it for conditional logic, or understand what information is attached to selected options.

Field Types

Custom fields support various data types, each suited for different use cases:

Text Fields

Text - Single-line text input for short information like product codes, reference numbers, or brief specifications.

Multi-line Text - Text area for longer content such as descriptions, specifications, or special instructions.

Translatable Text - Single-line text supporting multiple languages. Values are automatically resolved to the current locale.

Multi-line Translatable Text - Multi-line text area with translation support for localized descriptions or content.

Numeric Fields

Number - Numeric input for measurements, quantities, weights, or any numeric specifications.

Selection Fields

Single Select - Dropdown selection from predefined options. Useful for controlled vocabularies like materials, finishes, or grades.

Checkbox - Boolean field for yes/no choices, feature flags, or optional specifications.

File Fields

File - File upload for technical drawings, reference images, or documentation. Can be configured for single or multiple files.

Structured Fields

Meta Object - Grouped collection of multiple fields stored as structured data. Ideal for complex specifications like dimensions (width, height, depth, unit) or technical parameters grouped together.

Accessing Custom Field Definitions

Custom field definitions are available through the customer configuration observer. These definitions contain metadata about each field including its type, name, validation rules, and type-specific configuration.

window.mimeeqApp.observers.config.customerConfig.subscribe(({ newValue }) => {
if (newValue) {
const customFields = newValue.customFields;

// customFields is an array of field definitions
// Already translated to current locale
}
});

Each field definition includes:

  • key - Unique identifier for the field
  • name - Translated display name
  • type - Field type (TEXT, NUMBER, SINGLE_SELECT, etc.)
  • parameterId - System identifier
  • typeConfig - Type-specific configuration (e.g., options for SINGLE_SELECT fields)

Reading Custom Field Values (Metafields)

Custom field values are stored in the metafields property on options. These values are available both on option definitions within blocks and on selected options.

// From available options in blocks
window.mimeeqApp.observers.optionSets.blocks.subscribe(({ newValue }) => {
if (newValue) {
newValue.forEach(block => {
block.options?.forEach(option => {
const vendorCode = option.metafields?.vendorCode;
const thickness = option.metafields?.thickness;
});
});
}
});

// From selected options
window.mimeeqApp.observers.optionSets.selectedOptions.subscribe(({ newValue }) => {
if (newValue) {
const options = newValue.SINGLE_PRODUCT_ID || [];
options.forEach(option => {
const customValue = option.metafields?.customFieldKey;
});
}
});

Important Notes:

  • Metafields only exist on options that have custom field values assigned
  • Access metafields using dot notation: option.metafields.fieldKey
  • Text values are already translated to the current locale (or fallback language)
  • The flow: option with metafield → selected option retains metafield → used in SKU/pricing/UI

Working with Single Select Fields

Single Select fields store only the selected option's value in metafields. To display the human-readable label, you need to look it up from the field definition.

window.mimeeqApp.observers.config.customerConfig.subscribe(({ newValue }) => {
if (newValue) {
const customFields = newValue.customFields;

// Find the field definition
const materialField = customFields.find(f => f.key === 'material_type');

// Get the value from metafields (e.g., "aluminum")
const selectedValue = option.metafields?.material_type;

// Look up the label
const selectedOption = materialField?.typeConfig?.selectOptions?.find(
opt => opt.value === selectedValue
);

const displayLabel = selectedOption?.name; // "Aluminum" (translated)
}
});

The typeConfig.selectOptions array contains objects with:

  • value - The stored identifier (what's in metafields)
  • name - The translated display label (what users see)

Working with Meta Object Fields

Meta Object fields store structured data as an array of objects. Each object in the array contains an id and a fields object with the actual data.

// Example: dimensions META_OBJECT with width, height, depth fields
const dimensions = option.metafields?.dimensions;

if (dimensions && Array.isArray(dimensions)) {
dimensions.forEach(entry => {
// Access nested fields through the 'fields' property
const width = entry.fields.width;
const height = entry.fields.height;
const depth = entry.fields.depth;
const unit = entry.fields.unit;

console.log(`${width}x${height}x${depth} ${unit}`);
});
}

Meta Object structure:

  • Stored as array to support multiple instances
  • Each array entry has id (unique identifier) and fields (data object)
  • Access nested values: entry.fields.fieldName

Working with File Fields

File fields store file references as objects containing both an identifier and storage path. For multiple files, the value is an array of these objects.

// Single file
const technicalDrawing = option.metafields?.technical_drawing;

if (technicalDrawing) {
const fileId = technicalDrawing.fileId;
const filePath = technicalDrawing.filePath;

// Use filePath to display or download the file
const fileUrl = `${CDNPath}${filePath}`;
}

// Multiple files
const documents = option.metafields?.documentation;

if (documents && Array.isArray(documents)) {
documents.forEach(file => {
const url = `${CDNPath}${file.filePath}`;
// Create download links or preview images
});
}

File value structure:

  • fileId - Unique identifier for the file
  • filePath - Storage path (relative to CDN)
  • Single file: object
  • Multiple files: array of objects

Practical Example: Displaying Product Badges and Info

This example shows how to use custom fields to enhance product options with technical specifications and additional information, based on real-world usage patterns.

// Subscribe to available options
window.mimeeqApp.observers.optionSets.blocks.subscribe(({ newValue }) => {
if (newValue) {
newValue.forEach(block => {
block.options?.forEach(option => {
renderProductOption(option);
});
});
}
});

function renderProductOption(option) {
const container = document.createElement('div');
container.className = 'product-option';

// Display product name
const name = document.createElement('h3');
name.textContent = option.name;
container.appendChild(name);

// Display technical specifications from META_OBJECT
const specs = renderTechnicalSpecs(option);
if (specs) {
container.appendChild(specs);
}

// Display additional product info
const info = renderProductDescription(option);
if (info) {
container.appendChild(info);
}

// Display product gallery images from FILE field
const gallery = renderProductGallery(option);
if (gallery) {
container.appendChild(gallery);
}

document.getElementById('options-container').appendChild(container);
}

// Example 1: META_OBJECT field with technical specifications
function renderTechnicalSpecs(option) {
// META_OBJECT field storing structured technical data
const specsData = option.metafields?.['info-popup-data'];

if (!specsData || !Array.isArray(specsData) || specsData.length === 0) {
return null;
}

const specsContainer = document.createElement('div');
specsContainer.className = 'technical-specs';

const table = document.createElement('table');

// Each entry in the META_OBJECT array contains specification data
specsData.forEach(specEntry => {
const row = table.insertRow();

// Access nested field values from the META_OBJECT
const labelCell = row.insertCell(0);
labelCell.textContent = specEntry.fields['data-name']; // e.g., "Cores", "Socket"

const valueCell = row.insertCell(1);
valueCell.textContent = specEntry.fields.value; // e.g., "10 (6P + 4E)", "LGA1851"
});

specsContainer.appendChild(table);
return specsContainer;
}

// Example 2: Text field with product description
function renderProductDescription(option) {
// Text field already translated to current locale
const description = option.metafields?.['option-simple-info'];

if (!description) {
return null;
}

const descElement = document.createElement('p');
descElement.className = 'product-description';
descElement.textContent = description; // Already a string, ready to use

return descElement;
}

// Example 3: FILE field with product gallery
function renderProductGallery(option) {
// FILE field (array) storing multiple product images
const galleryFiles = option.metafields?.['product-gallery'];

if (!galleryFiles || !Array.isArray(galleryFiles) || galleryFiles.length === 0) {
return null;
}

const galleryContainer = document.createElement('div');
galleryContainer.className = 'product-gallery';

// Each file entry contains fileId and filePath
galleryFiles.forEach(fileEntry => {
const img = document.createElement('img');

// Construct full URL using CDN path and file path
const CDNPath = 'https://your-cdn.com/'; // Get from customerConfig
img.src = `${CDNPath}${fileEntry.filePath}`;
img.alt = option.name;

galleryContainer.appendChild(img);
});

return galleryContainer;
}

Key Patterns Demonstrated:

  1. META_OBJECT iteration - Loop through array entries and access nested fields using entry.fields.fieldName syntax
  2. Multiple field types - Combining META_OBJECT, text, and FILE fields in a single option
  3. Conditional rendering - Check if custom fields exist before attempting to render
  4. File path construction - Build complete URLs by combining CDN path with file paths from FILE fields
  5. Direct string access - Text fields are already translated and ready to use as strings