Package Exports
- @nine-slice-frame/vue
Readme
@nine-slice-frame/vue
Nine-slice scaling component for Vue 3 using CSS border-image
.
What is Nine-Slice Scaling?
Nine-slice scaling divides an image into 9 sections, allowing it to scale to any size while preserving corner details and preventing distortion. Perfect for UI frames, borders, panels, and buttons that need to scale dynamically.
┌─────────┬───────────┬─────────┐
│ Corner │ Top Edge │ Corner │
│ (Fixed) │ (Scale H) │ (Fixed) │
├─────────┼───────────┼─────────┤
│ Left │ Center │ Right │
│ Edge │ (Scale │ Edge │
│(Scale V)│ Both) │(Scale V)│
├─────────┼───────────┼─────────┤
│ Corner │ Bottom │ Corner │
│ (Fixed) │ Edge │ (Fixed) │
└─────────┴───────────┴─────────┘
Why Nine-Slice Scaling?
The Problem: Traditional image scaling stretches the entire image uniformly, distorting corners, borders, and decorative elements. This makes UI elements look unprofessional and breaks visual consistency.
The Solution: Nine-slice scaling keeps corners and edges crisp while only stretching the middle sections. This means:
- Single image, infinite sizes - One asset works for buttons, dialogs, and panels of any dimension
- Pixel-perfect corners - Ornate borders and rounded corners stay sharp at any scale
- Smaller file sizes - No need for multiple image variants for different sizes
- Ideal for pixel art - Preserves the crisp aesthetic of retro-style UIs
- CSS-native performance - Uses browser-native
border-image
, no canvas or WebGL overhead
Common Use Cases:
- Game UI frames and dialog boxes
- Decorative borders and panels
- Scalable buttons with ornate edges
- Retro/pixel art interfaces
- Dynamic content containers
Why This Library?
Zero Dependencies - No runtime dependencies beyond Vue. This package only requires Vue 3 as a peer dependency.
Incredibly Small - Minimal bundle impact: 1.33KB / 0.67KB gzipped
Native Performance - Uses browser-native CSS border-image
property, not canvas rendering or heavy image manipulation libraries. Fast, efficient, and hardware-accelerated.
Framework-Agnostic API - Same simple, consistent API across all frameworks:
- @nine-slice-frame/react
- @nine-slice-frame/vue (you are here)
- @nine-slice-frame/svelte
- @nine-slice-frame/solid
Installation
npm install @nine-slice-frame/vue
# or
pnpm add @nine-slice-frame/vue
# or
yarn add @nine-slice-frame/vue
Usage
<script setup lang="ts">
import { NineSliceFrame } from '@nine-slice-frame/vue';
</script>
<template>
<NineSliceFrame
image-path="/ui/frame.png"
:slice="7"
:border-width="5"
repeat="stretch"
:fill="true"
:pixelated="true"
>
<p>Your content here</p>
</NineSliceFrame>
</template>
Props
Prop | Type | Default | Description |
---|---|---|---|
image-path |
string |
required | Path to the image (relative to public folder) |
slice |
number | object |
8 |
Slice values - number for uniform, or { top, right, bottom, left } for per-edge |
border-width |
number |
5 |
Visual border width in pixels |
repeat |
'stretch' | 'repeat' | 'round' | 'space' |
'stretch' |
Border repeat mode |
fill |
boolean |
true |
Use 'fill' to show center of image as background |
pixelated |
boolean |
true |
Use pixelated rendering for pixel art |
class |
string |
'' |
Additional CSS class names |
style |
StyleValue |
{} |
Additional inline styles |
Note: Vue uses kebab-case for props in templates (image-path
, border-width
).
Advanced Usage
Different Slice Values Per Edge
<template>
<NineSliceFrame
image-path="/ui/fancy-frame.png"
:slice="{ top: 10, right: 8, bottom: 10, left: 8 }"
:border-width="6"
>
Content with asymmetric border
</NineSliceFrame>
</template>
Custom Styling
<template>
<NineSliceFrame
image-path="/ui/frame.png"
:slice="8"
:border-width="10"
class="my-custom-frame"
:style="{ padding: '20px', minHeight: '200px' }"
>
Styled content
</NineSliceFrame>
</template>
TypeScript
This package includes TypeScript definitions out of the box.
Requirements
- Vue >= 3.3.0
License
MIT © Callum Gander