Appearance
Tine Preset Support Pack
Diagnostic and troubleshooting reference for the Tine hardware preset — comparison table, specs-table mode, bulk pricing, and hardware metafields.
FAQ
Q: The comparison table columns are not sorting correctly.
A: The sort extracts the first numeric token from each cell value and compares numbers; values with no numeric token fall back to locale-aware string comparison. In practice:
- Metric threads sort correctly by number — M8 < M10 < M12 — with no zero-padding needed
- European decimal commas are normalized ("5,5 mm" sorts as 5.5)
- Composite codes like
A2-70sort by their first numeric token (2 in this example); if a standards-code column sorts surprisingly, keep its values in one consistent format
Q: The specs table mode is showing unsorted data in the wrong column.
A: In orientation: rows mode, the table renders spec name/value pairs from section blocks in the order they were added in the theme editor. The table is intentionally non-sortable in rows mode (sorting attribute names is not meaningful). To reorder rows, reorder the blocks in the theme editor.
Q: The bulk-pricing pill is showing but no discount is applied.
A: This is by design — the pill is a messaging display aid only. It does not apply a Shopify discount automatically. To apply actual discounts:
- Set up a quantity-break discount in Shopify (Discounts → Create discount → Amount off products → Minimum purchase quantity) or use a price-breaks app.
- Set the
bulk_thresholdin the Quick Order section to match your first discount tier quantity. - The pill will show the savings percentage informationally; the actual discount is applied at checkout by Shopify's discount engine.
Q: Quick order section renders no products.
A: The Quick Order section requires a collection to be selected. Check:
- In the theme editor, navigate to Quick Order → Section settings. Is a collection selected?
- Does the selected collection have at least one published product?
- If the collection is empty, the section shows a guided empty state — check your collection rules or populate products.
Q: Cross-reference block is not rendering.
A: The cross-reference block has no block settings. It reads only the uisce_tine.battery_compat product metafield — a /-separated list of compatible systems — and renders one list item per entry. When the metafield is blank, the block renders nothing. Populate battery_compat on the product in Shopify Admin.
Decision Tree: "Why is my comparison table not rendering?"
Symptom: Comparison table section appears but has no columns
-> Are there blocks added to the comparison table section?
-> In theme editor: Sections → Comparison table → check for column blocks
-> No blocks: add at least 2 comparison-column blocks
-> Yes: Continue
-> Is orientation set correctly?
-> 'columns' mode: expects multiple column blocks
-> 'rows' mode: expects spec-row blocks
-> Wrong block type for current orientation: switch to the matching block type
-> Are column headings empty?
-> Empty column heading will render but look invisible — check each block has a heading
-> Is the niche_metafield_namespace required for this section?
-> Comparison table does not read metafields directly — specs-table-row PDP blocks do
-> If metafield data not showing on PDP: check metafield definitions in Shopify AdminValidator Interpretation
"Lighthouse: Comparison table — interactive element does not have an accessible name"
The comparison table sort buttons are <button> elements wrapping <th> text. If Lighthouse flags this, the button may lack an aria-label. Check that each sortable column header's <button> has either visible text content or an aria-label that names the sort action. The theme ships aria-label="Sort by {column}" — verify this is present in the rendered HTML.
"axe: aria-sort value is not allowed"
The comparison table uses aria-sort="ascending" and aria-sort="descending" per ARIA spec. Valid values are none, ascending, descending, other. If axe flags this, a custom edit may have introduced an invalid value. The sort click handler in niche-tine.js resets every column header to aria-sort="none" and then sets the active <th> to ascending or descending — those are the only values the theme writes.
"Theme check: quick-order section missing collection setting"
This is expected in a fresh install before the merchant selects a collection. Select a collection on the Quick Order section in the theme editor — collection settings cannot take a schema default on Shopify, so a selection is always required. Until one is selected the section renders its guided empty state.
Console Diagnostic Snippet
js
(function tineDiagnostic() {
'use strict';
const compTable = document.querySelector('.comparison-table');
const r = {
presetBodyClass: document.body.classList.contains('preset-tine'),
comparisonTable: {
present: !!compTable,
mode: compTable ? (compTable.classList.contains('comparison-table--rows') ? 'rows' : 'columns') : 'not found',
columnHeaders: document.querySelectorAll('.comparison-table__col-header').length,
valueCells: document.querySelectorAll('.comparison-table__value').length,
mobileCards: document.querySelectorAll('.comparison-table__card').length,
sortableHeaders: document.querySelectorAll('th[aria-sort]').length,
lastAriaSortValue:
document.querySelector('th[aria-sort]:not([aria-sort="none"])')?.getAttribute('aria-sort') ?? 'none',
},
quickOrder: {
present: !!document.querySelector('.quick-order'),
rowCount: document.querySelectorAll('.quick-order__row').length,
bulkPillActive: !!document.querySelector('.quick-order__quantity-break-pill--active'),
},
nicheTineMounted: !!document.querySelector('niche-renderer[data-preset="tine"]'),
presetCSS: !!document.querySelector('link[href*="preset-tine"]'),
nicheNamespace: document.querySelector('[data-niche-namespace]')?.dataset?.nicheNamespace ?? 'not found',
};
console.group('%cTine Diagnostic Report', 'color:#c0392b;font-weight:bold;font-size:14px');
console.table(r.comparisonTable);
console.log('Quick order:', r.quickOrder);
// niche-tine.js loads via dynamic import — there is no <script> element to probe
console.log('niche-renderer mounted:', r.nicheTineMounted);
console.log('Preset CSS:', r.presetCSS);
console.groupEnd();
return r;
})();Accessibility Diagnostic
Comparison table sort accessibility check
js
(function checkComparisonTableA11y() {
const table = document.querySelector('.comparison-table table');
if (!table) {
console.warn('No comparison table found');
return;
}
const sortHeaders = table.querySelectorAll('th[aria-sort]');
const liveRegion = document.querySelector('[data-comparison-table-announce]');
console.log({
tablePresent: true,
sortableColumns: sortHeaders.length,
ariaSortValues: [...sortHeaders].map((th) => th.getAttribute('aria-sort')),
liveRegionPresent: !!liveRegion,
liveRegionPolite: liveRegion?.getAttribute('aria-live') === 'polite',
caption: table.querySelector('caption')?.textContent?.trim() ?? 'MISSING',
});
})();Expected: sortableColumns > 0 (when sorting is enabled), aria-sort values in none/ascending/descending, liveRegionPresent and liveRegionPolite true. aria-sort sits on the <th> itself (a descendant probe like th [aria-sort] matches nothing), and the announcer is a visually-hidden aria-live="polite" span — it carries no role="status".
Quick order bulk pill check
js
const pills = document.querySelectorAll('.quick-order__quantity-break-pill');
const bulkAnnounce = document.querySelector('[data-bulk-announce]');
console.log({
pillCount: pills.length,
activePills: [...pills].filter((p) => p.classList.contains('quick-order__quantity-break-pill--active')).length,
ariaHiddenStates: [...pills].map((p) => p.getAttribute('aria-hidden')),
liveRegionPresent: !!bulkAnnounce,
pillText: pills[0]?.textContent?.trim() ?? 'none rendered',
});Pills only render when bulk_threshold > 0; visibility toggles via the quick-order__quantity-break-pill--active class plus aria-hidden (not the hidden attribute).
Localization Notes
Comparison table locale keys
The sort button's accessible name uses sections.comparison_table.sort_button_aria ("Sort by {column}"). Sort announcements are assembled from sections.comparison_table.announce_sorted_by, announce_direction_ascending, announce_direction_descending, and announce_column_fallback. All 50 locales covered.
Quick order bulk-pricing pill keys
The pill label uses sections.quick_order.bulk_pill ("Save %"); the screen-reader announcement uses sections.quick_order.announce_bulk_save. Check both are translated correctly for your non-EN markets.
Specs-table PDP block keys
The specs-table-row PDP block strings live under blocks.specs-table-row.* (hyphenated namespace).
Standards names are not localized
Technical standards designations (ASTM F3125, ISO 898-1, DIN EN ISO 7045, BS EN ISO) are English-language designations recognized internationally. They should NOT be translated — use the official designation string verbatim as the spec value. If you need to explain a standard in a customer-facing description, add a richtext block in your product description.
Curl Cheat-Sheet
bash
# Verify Product + additionalProperty JSON-LD on a hardware product
curl -s "https://your-store.myshopify.com/products/tine-cap-screw-m8-50-a2" \
| grep -A 15 '"additionalProperty"'
# Check data-niche-namespace on the comparison table (ships on the homepage)
curl -s "https://your-store.myshopify.com" \
| grep 'data-niche-namespace'
# Verify preset-tine.css is linked
curl -s "https://your-store.myshopify.com" \
| grep 'preset-tine'
# Check aria-sort attribute is present on the comparison table (homepage)
curl -s "https://your-store.myshopify.com" \
| grep 'aria-sort'Deployment Checklist
Before going live with the Tine preset:
- [ ]
settings.presetset totinein Theme settings - [ ] Comparison table has at least 2 column or 2 row blocks populated
- [ ]
orientationsetting is set to the correct mode for each table usage context - [ ] Quick order section has a collection selected
- [ ]
bulk_thresholdandbulk_save_percentmatch your actual pricing tier - [ ] Product metafield definitions for
uisce_tine.*created in Shopify Admin - [ ] At least 4 products have
materialanddimensions_mmmetafields populated - [ ] Header menu includes product navigation and a link to the quick-order page (
page.trade-ordertemplate); the comparison table ships on the homepage — no separate compare page exists - [ ] JSON-LD validated: Product + additionalProperty appears on product pages
- [ ] Comparison table aria-sort is verified: run diagnostic snippet above
- [ ]
preset-tine.csslinked: confirmed via curl check above
Support pack last updated: 2026-05-03 (Phase 06.10 closeout)