Scale & Centering API
comp-hub Only
$getScaleStyle and $onScaleChange are injected by comp-hub's preview environment. They are NOT standard Vue APIs and do not exist in a normal Vue project locally. If you use these APIs in your component, make sure to guard against them being undefined when running outside comp-hub.
In the preview panel, comp-hub provides two methods on your component's Vue instance to help adapt content to the preview container:
$getScaleStyle— query the current scale and position transform$onScaleChange— subscribe to container size changes and automatically get the latest style
$getScaleStyle(params) → Style
Synchronously query the computed scale & position style based on your component's content dimensions and scaling mode.
type ScaleMode = "widthFirst" | "heightFirst" | "contain" | "cover"
interface ScaleStyle {
transform: string // e.g. "translate(100px, 50px) scale(0.75)"
transformOrigin: string // always "left top"
}
this.$getScaleStyle({
mode: ScaleMode // scaling mode
width: number // your component content width (px)
height: number // your component content height (px)
}): ScaleStyleUsage (Vue 2 Options API)
<template>
<div :style="$getScaleStyle({ mode: 'contain', width: 800, height: 500 })">
<!-- component content -->
</div>
</template>Usage (Vue 3 Composition API)
import { getCurrentInstance } from "vue"
const instance = getCurrentInstance()
const scaleStyle = instance.proxy.$getScaleStyle({
mode: "contain",
width: 800,
height: 500
})Scaling Modes
| Mode | Behavior |
|---|---|
"widthFirst" | Scale to fit container width, height may overflow |
"heightFirst" | Scale to fit container height, width may overflow |
"contain" | Scale proportionally, content fully visible within container (recommended default) |
"cover" | Scale proportionally, content fills container (may clip excess) |
All modes center the content inside the container via translate.
$onScaleChange(params, callback) → unsubscribe
Subscribes to container size changes. The callback is invoked immediately with the current scale, then again whenever the container is resized.
const unsubscribe = this.$onScaleChange(
params: { mode: ScaleMode, width: number, height: number },
callback: (style: ScaleStyle) => void
): () => voidUsage (Vue 2 Options API)
<script>
export default {
data() {
return { scaleStyle: {} }
},
mounted() {
// Persist content dimensions
this.contentSize = { width: 800, height: 500 }
// Subscribe — auto-recalculates on container resize
this._unsub = this.$onScaleChange(
{ mode: "contain", width: 800, height: 500 },
(style) => { this.scaleStyle = style }
)
},
beforeDestroy() {
this._unsub?.() // Clean up subscription
}
}
</script>Usage (Vue 3 Composition API)
<script setup>
import { ref, getCurrentInstance, onBeforeUnmount } from "vue"
const instance = getCurrentInstance()
const scaleStyle = ref({})
const unsub = instance.proxy.$onScaleChange(
{ mode: "contain", width: 800, height: 500 },
(style) => { scaleStyle.value = style }
)
onBeforeUnmount(() => unsub())
</script>Common Patterns
Demo Component with Fixed Content Size
Preview demo components typically declare a fixed content area, then use the scale API to fill the preview panel:
<template>
<div class="demo-wrapper" :style="scaleStyle">
<!-- Content designed to 800×500 -->
<div class="demo-content">...</div>
</div>
</template>
<script>
export default {
data() {
return { scaleStyle: {} }
},
mounted() {
this._unsub = this.$onScaleChange(
{ mode: "contain", width: 800, height: 500 },
(style) => { this.scaleStyle = style }
)
},
beforeDestroy() {
this._unsub?.()
}
}
</script>
<style scoped>
.demo-wrapper {
transform-origin: left top;
}
.demo-content {
width: 800px;
height: 500px;
overflow: hidden;
}
</style>Best Practices
- Subscribe, don't poll — use
$onScaleChangefor responsive layouts instead of calling$getScaleStylerepeatedly - Clean up subscriptions — always call
unsubscribe()inbeforeDestroy/onBeforeUnmountto prevent memory leaks - Fixed content size — design your demo with a specific width × height (e.g., 800×500) and let the scale API handle the rest
containis the safe default — it ensures all content is visible even in small panels- Guard for non-comp-hub environments — since these APIs only exist inside comp-hub preview, always check if they are available before calling:
// Safe calling pattern
if (this.$getScaleStyle) {
this.scaleStyle = this.$getScaleStyle({ mode: "contain", width: 800, height: 500 })
}
if (this.$onScaleChange) {
this._unsub = this.$onScaleChange(
{ mode: "contain", width: 800, height: 500 },
(style) => { this.scaleStyle = style }
)
}