News
OluKai and HLA Presents: On Guard Episode 5
On Guard - Episode 5 with Kamakani Froiseth and Chelsea Bizik
In the latest chapter of On Guard, we head to the island of Oʻahu to follow Kamakani Froiseth and Chelsea Bizik, a power couple dedicated to saving lives and raising their children in the ocean.
Kamakani, a multi-generational lifeguard hailing from the West Side, runs the rescue ski in some of the heaviest conditions on the island.
Chelsea, a lieutenant and accomplished open-ocean paddler from the East Side, manages the systems and teams that forge the backbone of daily operations.
Together, they balance frontline duty with raising two children, ensuring that the next generation grows up with a strong connection to the ocean and a deep respect for the islands they call home.
Shop The Story
{"id":8520010137735,
"handle":"ahi-kai-mens-beach-sandals-black",
"title":"ʻAhi Kai - Black \/ Black",
"available":true,
"tags":["71'ahi kai - m","ahi kai","Ahi Kai Sandals","ahikai","ahikai men sandals","arch:standard","beach","beach sandals","Beach\/Boat","breathable","cat:sandals","Dark Soled","enhanced traction footbed","enhanced traction outsole","fit:standard","fli p flflop men","flip flops","gender:men","just in","lightweight","material:synthetic","men","men beach sandals","men's beach sandals","mens","mens sandals","Mens sansandals","men’s","olukai beach sandals","Rgroup_10571","sandals","shearling lined","size:true","split_color","style:10571","synthetic","textile","vegan","water sandals mens","water-friendly","water-resistant","waterproof"],
"type":"Men’s Beach Sandals",
"options_with_values": [{"name":"Color","position":1,"values":["Black \/ Black"]},{"name":"Size","position":2,"values":["7","8","9","10","11","12","13","14","15"]}],
"price":12000,
"price_min":12000,
"price_max":12000,
"compare_at_price":null,"featured_image": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_001_M_AHIKAI_BlackBlack.png?v=1774911717",
"featured_image_aspect_ratio": 1.0,
"featured_image_width": 2000,
"featured_image_height": 2000,
"featured_image_id": 42001200119943,
"featured_image_alt": "ʻAhi Kai - Black \/ Black",
"hover_image": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_105_M_AHIKAI_BlackBlack.png?v=1774911720",
"hover_image_alt": "ʻAhi Kai - Black \/ Black",
"images": [{
"id": 42001200119943,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_001_M_AHIKAI_BlackBlack.png?v=1774911717",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001200316551,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_105_M_AHIKAI_BlackBlack.png?v=1774911720",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001200906375,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571-4040-101.jpg?v=1774911717",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001201004679,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_102_M_AHIKAI_BlackBlack.png?v=1774911718",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001201397895,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571-4040-102.jpg?v=1774911718",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001202774151,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_103_M_AHIKAI_BlackBlack.png?v=1774911719",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001203232903,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_003_M_AHIKAI_BlackBlack.png?v=1774911719",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001203789959,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_004_M_AHIKAI_BlackBlack.png?v=1774911720",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
},{
"id": 42001203921031,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10571_4040_005_M_AHIKAI_BlackBlack.png?v=1774911721",
"alt": "ʻAhi Kai - Black \/ Black",
"width": 2000,
"height": 2000
}],
"plp_image_order_positions": "",
"sku": "10571-4040-7"
}
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
{"id":8134359122055,
"handle":"makiki-mens-athletic-shoes-cloud-grey-poi",
"title":"Makiki - Cloud Grey \/ Poi",
"available":true,
"tags":["arch:standard","best seller","best selling","best:everday_wear","best:travel","boat shoe","boatshoes","cat:shoes","color:blue","drop-in heel®","enhance gip","enhanced traction outsole","Everyday Wear","fit:standard","free shipping","gender:men","labor day","landtextile","likes:beach","likes:exercising","likes:friends","likes:hiking","likes:relaxing","likes:urban-exploring","makiki","makiki olukai","makiki shoes for sea","material:textile","mens","mesh","no shoestring","RGroup_10567","shoes","size:true","sneakers","split_color","style:10567","swim","swim shoes","Travel","vegan","water-friendly","wide toed","wide width"],
"type":"Men’s Athletic Shoes",
"options_with_values": [{"name":"Color","position":1,"values":["Cloud Grey \/ Poi"]},{"name":"Size","position":2,"values":["7","8","8.5","9","9.5","10","10.5","11","11.5","12","13","14","15"]}],
"price":18000,
"price_min":18000,
"price_max":18000,
"compare_at_price":null,"featured_image": "\/\/olukai.ca\/cdn\/shop\/files\/10567_2N25_001_M_MAKIKI_CloudGreyPoi_f4b5d736-60bd-465a-b5a0-4780b9efe973.png?v=1759467643",
"featured_image_aspect_ratio": 1.0,
"featured_image_width": 2000,
"featured_image_height": 2000,
"featured_image_id": 35110507217031,
"featured_image_alt": "Cloud Grey \/ Poi",
"hover_image": "\/\/olukai.ca\/cdn\/shop\/files\/10567-2N25-202.jpg?v=1751320159",
"hover_image_alt": "Makiki - Cloud Grey \/ Poi",
"images": [{
"id": 35110507217031,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10567_2N25_001_M_MAKIKI_CloudGreyPoi_f4b5d736-60bd-465a-b5a0-4780b9efe973.png?v=1759467643",
"alt": "Cloud Grey \/ Poi",
"width": 2000,
"height": 2000
},{
"id": 35180883509383,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10567-2N25-202.jpg?v=1751320159",
"alt": "Makiki - Cloud Grey \/ Poi",
"width": 2000,
"height": 2000
},{
"id": 35110507249799,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10567_2N25_003_M_MAKIKI_CloudGreyPoi_1806c052-4b56-4ca7-a824-1a889b780abd.png?v=1751320159",
"alt": "Cloud Grey \/ Poi",
"width": 2000,
"height": 2000
},{
"id": 35180881543303,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10567-2N25-201.jpg?v=1751320159",
"alt": "Makiki - Cloud Grey \/ Poi",
"width": 2000,
"height": 2000
},{
"id": 35110507282567,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10567_2N25_004_M_MAKIKI_CloudGreyPoi_85d5203c-d7aa-43e9-96b2-d3384cdcf099.png?v=1751320158",
"alt": "Cloud Grey \/ Poi",
"width": 2000,
"height": 2000
},{
"id": 35110507348103,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/10567_2N25_005_M_MAKIKI_CloudGreyPoi_e42c63f4-1f7a-403e-bddf-c7734400bc7a.png?v=1751320158",
"alt": "Cloud Grey \/ Poi",
"width": 2000,
"height": 2000
}],
"plp_image_order_positions": "",
"sku": "10567-2N25-7"
}
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
{"id":5156404789383,
"handle":"ohana-womens-beach-sandals-black",
"title":"‘Ohana - Black",
"available":true,
"tags":["'ohanna","2024-gift-guide","arch:high","beach sandals","Beach\/Boat","beachbum","best sellers","best selling","best:beach_boat","best:everday_wear","black fliflps","cat:sandals","collection:chief-home-officer","collection:HGG-Slider-W","collection:tide-tracker","color:Black","enhanced traction outsole","Everyday Wear","EXP_REC_WOMEN","extra-colors","fit:wide","flip flops","gender:women","labor day","likes:beach","material:synthetic","mothers-day","nature-inspired","o hana","o hanas","obama","oha","Ohana","ohana w","ohanaflip flops","ohanaohana women","ohsna","omaha","prime","RGroup_20110","size:true","SP-19-COLOR","SP19-Style","split_color","style:20110","synthetic","vacation:tropical","vegan","vegan friendly","water-friendly","wide sizes","wide width","widewidh","women","womens","womensflip flop","women’s","YGroup_20110","‘ohani"],
"type":"Women’s Water-Friendly Sandals",
"options_with_values": [{"name":"Color","position":1,"values":["Black"]},{"name":"Size","position":2,"values":["5","6","7","8","9","10","11","12"]}],
"price":10000,
"price_min":10000,
"price_max":10000,
"compare_at_price":null,"featured_image": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_001_W_Ohana_BlkBlk_41e6f1b8-ca5c-4d05-94b5-8f99b86192d1.png?v=1762441470",
"featured_image_aspect_ratio": 1.0,
"featured_image_width": 2000,
"featured_image_height": 2000,
"featured_image_id": 34400636043399,
"featured_image_alt": "Black",
"hover_image": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_102_W_OHANA_BlackBlack_29477e0f-6d55-47ce-a8a2-5d3cc7b3e441.jpg?v=1746734998",
"hover_image_alt": "Black",
"images": [{
"id": 34400636043399,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_001_W_Ohana_BlkBlk_41e6f1b8-ca5c-4d05-94b5-8f99b86192d1.png?v=1762441470",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636076167,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_102_W_OHANA_BlackBlack_29477e0f-6d55-47ce-a8a2-5d3cc7b3e441.jpg?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636108935,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_201_3d4a23f2-2dc2-4377-b783-2facd28f27cc.jpg?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636141703,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_105_W_OHANA_BlackBlack_9583fbfc-e266-4f84-8cb7-6bea1e1d83ea.jpg?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636174471,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_103_W_OHANA_BlackBlack_544bdd54-9555-4ff7-8502-0d553b48c511.jpg?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636207239,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_202_c9aea4c7-0925-4de5-8e8c-6ddc4cb76f70.jpg?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636240007,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_004_W_Ohana_BlkBlk.png?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636272775,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_203_3b915de6-8cff-43d6-b402-12306bad97cf.jpg?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
},{
"id": 34400636305543,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20110_4040_005_W_Ohana_BlkBlk.png?v=1746734998",
"alt": "Black",
"width": 2000,
"height": 2000
}],
"plp_image_order_positions": "",
"sku": "20110-4040-5"
}
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
{"id":8134359023751,
"handle":"makiki-womens-athletic-shoes-lava-rock-dark-shadow",
"title":"Makiki - Lava Rock \/ Dark Shadow",
"available":true,
"tags":["49makiki - w","arch:standard","best:travel","bestselling","breathable","cat:shoes","drop-in heel®","everyday sneaker","Everyday Wear","fit:standard","free shipping","gender:women","landtextile","material:textile","mesh","mesh footwear","mesh shoe","removable footbed","rgroup:20549","Rgroup_20549","shoes","size:true","sneaker","sneakers","split_color","style:20549","style:2womens","textile","Travel","women","womens"],
"type":"Women’s Athletic Shoes",
"options_with_values": [{"name":"Color","position":1,"values":["Lava Rock \/ Dk Shadow"]},{"name":"Size","position":2,"values":["5","6","6.5","7","7.5","8","8.5","9","9.5","10","11"]}],
"price":18000,
"price_min":18000,
"price_max":18000,
"compare_at_price":null,"featured_image": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C_001_W_MAKIKI_LavaRockDkShadow.png?v=1759467642",
"featured_image_aspect_ratio": 1.0,
"featured_image_width": 2000,
"featured_image_height": 2000,
"featured_image_id": 35110506791047,
"featured_image_alt": "Lava Rock \/ Dk Shadow",
"hover_image": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C-202.jpg?v=1751392274",
"hover_image_alt": "Makiki - Lava Rock \/ Dark Shadow",
"images": [{
"id": 35110506791047,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C_001_W_MAKIKI_LavaRockDkShadow.png?v=1759467642",
"alt": "Lava Rock \/ Dk Shadow",
"width": 2000,
"height": 2000
},{
"id": 35180875743367,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C-202.jpg?v=1751392274",
"alt": "Makiki - Lava Rock \/ Dark Shadow",
"width": 2000,
"height": 2000
},{
"id": 35180879904903,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549-LR6C-101.jpg?v=1751392274",
"alt": "Makiki - Lava Rock \/ Dark Shadow",
"width": 2000,
"height": 2000
},{
"id": 35110506823815,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C_003_W_MAKIKI_LavaRockDkShadow.png?v=1751392274",
"alt": "Lava Rock \/ Dk Shadow",
"width": 2000,
"height": 2000
},{
"id": 35180877906055,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C-204.jpg?v=1751392274",
"alt": "Makiki - Lava Rock \/ Dark Shadow",
"width": 2000,
"height": 2000
},{
"id": 35180866732167,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549-LR6C-102.jpg?v=1751392274",
"alt": "Makiki - Lava Rock \/ Dark Shadow",
"width": 2000,
"height": 2000
},{
"id": 35110506856583,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C_004_W_MAKIKI_LavaRockDkShadow.png?v=1751392274",
"alt": "Lava Rock \/ Dk Shadow",
"width": 2000,
"height": 2000
},{
"id": 35180875088007,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C-205.jpg?v=1751392274",
"alt": "Makiki - Lava Rock \/ Dark Shadow",
"width": 2000,
"height": 2000
},{
"id": 35180867256455,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549-LR6C-103.jpg?v=1751392274",
"alt": "Makiki - Lava Rock \/ Dark Shadow",
"width": 2000,
"height": 2000
},{
"id": 35110506889351,
"src": "\/\/olukai.ca\/cdn\/shop\/files\/20549_LR6C_005_W_MAKIKI_LavaRockDkShadow.png?v=1751392274",
"alt": "Lava Rock \/ Dk Shadow",
"width": 2000,
"height": 2000
}],
"plp_image_order_positions": "",
"sku": "20549-LR6C-5"
}
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>
Explore Similar Stories
{ $dispatch('product-item:images-changed', { product: product, source: 'swatch-container' }) })"
@pointercancel="intendedSwatchIndex = null; intendedSwatchEl = null"
x-data="{
wrapper: $el,
selectedSibling:product.siblings[0],
intendedSwatchIndex: null,
intendedSwatchEl: null,
swatchGap: 8,
scrollable: product.siblings.filter(s => !!s.available).length > 9.5,
canPrev: false,
canNext: true,
_edgeReady: false,
imageLimit: 0,
limitImages(nextProduct) {
const images = Array.isArray(nextProduct && nextProduct.images) ? nextProduct.images : [];
const limitedImages = this.imageLimit > 0 ? images.slice(0, this.imageLimit) : images;
const hoverImage = limitedImages[1] || null;
return Object.assign({}, nextProduct, {
images: limitedImages,
hover_image: hoverImage ? hoverImage.src : null,
hover_image_alt: hoverImage ? hoverImage.alt : null
});
},
selectProduct(nextProduct) {
const productRoot = $el.closest('.product-item');
const productData = productRoot && productRoot._x_dataStack && productRoot._x_dataStack[0];
if (productData && typeof productData.setProduct === 'function') {
productData.setProduct(nextProduct);
} else {
$data.product = this.limitImages(nextProduct);
}
},
getSwatchImageSrc(sibling) {
return sibling.images[0].src;
},
buildSwatchSrcset(src) {
if (!src) return '';
const widths = ['48', '96', '192'];
const separator = src.includes('?') ? '&' : '?';
return widths.map(w => `${src}${separator}width=${w} ${w}w`).join(', ');
},
isSwatchPriority(index) {
return window.innerWidth >= 1024 ? index < 3 : index < 2;
},
swatchBg(sibling) {
// swatch_bg precomputed at hydration. Nullish (not ||): null = no colors set
// (fall back to theme default), empty string = invalid combo, no fallback.
return sibling.swatch_bg ?? '#000000';
},
centerSwatch(el) {
if ($data.wrapper.scrollWidth <= $data.wrapper.clientWidth) return false
const wrapperRect = $data.wrapper.getBoundingClientRect()
const elRect = el.getBoundingClientRect()
const centerPoint = wrapperRect.x + (wrapperRect.width / 2)
const behavior = window.innerWidth < 1024 ? 'auto' : 'smooth'
$data.wrapper.scrollTo({
left: $data.wrapper.scrollLeft + (elRect.x - centerPoint + (elRect.width / 2)),
behavior
})
},
selectSwatchFromTap(siblingIndex, el) {
const idx = (this.intendedSwatchIndex !== null && this.intendedSwatchIndex !== undefined)
? this.intendedSwatchIndex
: siblingIndex
const targetEl = this.intendedSwatchEl || el
this.intendedSwatchIndex = null
this.intendedSwatchEl = null
const next = product.siblings[idx]
if (next) product = next
this.centerSwatch(targetEl)
},
scroll(direction = 'forward') {
const swatch = $data.wrapper.querySelector('.product-item__swatch')
const unit = swatch ? swatch.offsetWidth + $data.swatchGap : $data.wrapper.clientWidth * 0.3
let amount = 2 * unit
$data.wrapper.scrollTo({
left: direction == 'forward' ? $data.wrapper.scrollLeft + amount : $data.wrapper.scrollLeft - amount,
behavior:'smooth'
})
},
// Lazily wire the prev/next edge detection on first desktop hover/focus —
// the arrows are a desktop affordance, so no observer is built at load and
// none is ever built on mobile. canPrev/canNext default to the at-start state.
initSwatchEdges() {
if (this._edgeReady || window.innerWidth <= 1023) return
this._edgeReady = true
const root = this.wrapper
const swatches = root.querySelectorAll('.product-item__swatch')
if (swatches.length < 2) return
const first = swatches[0], last = swatches[swatches.length - 1]
const io = new IntersectionObserver((entries) => {
const d = window.Alpine && window.Alpine.$data ? window.Alpine.$data(root) : null
if (!d) return
entries.forEach((e) => {
if (e.target === first) d.canPrev = !e.isIntersecting
if (e.target === last) d.canNext = !e.isIntersecting
})
}, { root, threshold: 0.99 })
io.observe(first)
io.observe(last)
root._swatchEdgeIO = io
}
}"
@pointerenter="initSwatchEdges()"
@focusin="initSwatchEdges()"
>