Scale & Centering API
comp-hub Only
$onScaleChange is injected by comp-hub's preview environment. It is NOT a standard framework API and does not exist outside comp-hub. For Vue components it is added to the Vue instance (this.$onScaleChange), and for React components it is passed as a prop onScaleChange. If you use this API in your component, make sure to guard against it being undefined when running outside comp-hub.
$onScaleChange subscribes to container size changes and automatically computes scale & centering styles, helping content adapt to the preview container.
Why Scaling?
The mini preview panel has limited space (typically around 300×200), but some components display rich content (charts, tables, complex form layouts, etc.). Without scaling, only a partial area is visible in the mini panel, making it impossible to see the full component. The scale API lets you define a preset content size (e.g., 800×500) and automatically scales it to fit the mini container, keeping everything visible.
type ScaleMode = "widthFirst" | "heightFirst" | "contain" | "cover"
interface ScaleStyle {
transform: string // e.g. "translate(100px, 50px) scale(0.75)"
transformOrigin: string // always "left top"
}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 (React)
The React version of the scale API is passed as a prop onScaleChange to your demo component:
import React, { useEffect, useState } from "react";
const DemoMini = ({ onScaleChange }) => {
const [scaleStyle, setScaleStyle] = useState({});
useEffect(() => {
if (onScaleChange) {
const unsubscribe = onScaleChange(
{ mode: "contain", width: 800, height: 500 },
(style) => setScaleStyle(style)
);
return unsubscribe; // cleanup on unmount
}
}, [onScaleChange]);
return (
<div style={scaleStyle}>
{/* your content */}
</div>
);
};
export default DemoMini;Usage (Vue 2 Options API)
<script>
export default {
data() {
return { scaleStyle: {} }
},
mounted() {
// 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
- 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 this API only exists inside comp-hub preview, always check if it's available before calling:
// Safe calling pattern
if (this.$onScaleChange) {
this._unsub = this.$onScaleChange(
{ mode: "contain", width: 800, height: 500 },
(style) => { this.scaleStyle = style }
)
}