Skip to content

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.

ts
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)
}): ScaleStyle

Usage (Vue 2 Options API)

vue
<template>
  <div :style="$getScaleStyle({ mode: 'contain', width: 800, height: 500 })">
    <!-- component content -->
  </div>
</template>

Usage (Vue 3 Composition API)

ts
import { getCurrentInstance } from "vue"

const instance = getCurrentInstance()
const scaleStyle = instance.proxy.$getScaleStyle({
  mode: "contain",
  width: 800,
  height: 500
})

Scaling Modes

ModeBehavior
"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.

ts
const unsubscribe = this.$onScaleChange(
  params: { mode: ScaleMode, width: number, height: number },
  callback: (style: ScaleStyle) => void
): () => void

Usage (Vue 2 Options API)

vue
<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)

vue
<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:

vue
<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

  1. Subscribe, don't poll — use $onScaleChange for responsive layouts instead of calling $getScaleStyle repeatedly
  2. Clean up subscriptions — always call unsubscribe() in beforeDestroy / onBeforeUnmount to prevent memory leaks
  3. Fixed content size — design your demo with a specific width × height (e.g., 800×500) and let the scale API handle the rest
  4. contain is the safe default — it ensures all content is visible even in small panels
  5. Guard for non-comp-hub environments — since these APIs only exist inside comp-hub preview, always check if they are available before calling:
js
// 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 }
  )
}

Components uploaded by users are open source