npm package: @nine-slice-frame/vue
Description: Nine-slice scaling component for Vue 3 using CSS border-image
Author: Callum Gander
Latest version: 1.0.0

# @nine-slice-frame/vue

[![npm version](https://img.shields.io/npm/v/@nine-slice-frame/vue.svg)](https://www.npmjs.com/package/@nine-slice-frame/vue)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Nine-slice scaling component for Vue 3 using CSS `border-image`.

🎯 **[Live Demo & Tester Tool](https://callum-gander.github.io/nine-slice-frame/)**

## 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](https://www.npmjs.com/package/@nine-slice-frame/react)
- [@nine-slice-frame/vue](https://www.npmjs.com/package/@nine-slice-frame/vue) (you are here)
- [@nine-slice-frame/svelte](https://www.npmjs.com/package/@nine-slice-frame/svelte)
- [@nine-slice-frame/solid](https://www.npmjs.com/package/@nine-slice-frame/solid)

## Installation

```bash
npm install @nine-slice-frame/vue
# or
pnpm add @nine-slice-frame/vue
# or
yarn add @nine-slice-frame/vue
```

## Usage

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

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

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

## Links

- [Main Repository](https://github.com/callum-gander/nine-slice-frame)
- [Live Demo](https://callum-gander.github.io/nine-slice-frame/)
- [Report Issues](https://github.com/callum-gander/nine-slice-frame/issues)