Modern nine-slice scaling components for React, Vue, Svelte, and Solid using CSS border-image
.
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) ā
āāāāāāāāāāā“āāāāāāāāāāāā“āāāāāāāāāā
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:
border-image
, no canvas or WebGL overheadCommon Use Cases:
Zero Dependencies - No runtime dependencies beyond your framework of choice. Each package only requires its respective framework as a peer dependency.
Incredibly Small - Minimal bundle impact with tiny package sizes:
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 React, Vue, Svelte, and Solid. Learn once, use everywhere.
npm install @nine-slice-frame/react
# or
pnpm add @nine-slice-frame/react
# or
yarn add @nine-slice-frame/react
npm install @nine-slice-frame/vue
# or
pnpm add @nine-slice-frame/vue
# or
yarn add @nine-slice-frame/vue
npm install @nine-slice-frame/svelte
# or
pnpm add @nine-slice-frame/svelte
# or
yarn add @nine-slice-frame/svelte
npm install @nine-slice-frame/solid
# or
pnpm add @nine-slice-frame/solid
# or
yarn add @nine-slice-frame/solid
import { NineSliceFrame } from '@nine-slice-frame/react';
function App() {
return (
<NineSliceFrame
imagePath="/ui/frame.png"
slice={7}
borderWidth={5}
repeat="stretch"
fill={true}
pixelated={true}
>
<p>Your content here</p>
</NineSliceFrame>
);
}
<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>
<script lang="ts">
import { NineSliceFrame } from '@nine-slice-frame/svelte';
</script>
<NineSliceFrame
imagePath="/ui/frame.png"
slice={7}
borderWidth={5}
repeat="stretch"
fill={true}
pixelated={true}
>
<p>Your content here</p>
</NineSliceFrame>
import { NineSliceFrame } from '@nine-slice-frame/solid';
function App() {
return (
<NineSliceFrame
imagePath="/ui/frame.png"
slice={7}
borderWidth={5}
repeat="stretch"
fill={true}
pixelated={true}
>
<p>Your content here</p>
</NineSliceFrame>
);
}
Prop | Type | Default | Description |
---|---|---|---|
imagePath |
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 |
borderWidth |
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 |
className |
string |
'' |
Additional CSS class names |
style |
React.CSSProperties |
{} |
Additional inline styles |
<NineSliceFrame
imagePath="/ui/fancy-frame.png"
slice={{ top: 10, right: 8, bottom: 10, left: 8 }}
borderWidth={6}
>
Content with asymmetric border
</NineSliceFrame>
This is a monorepo managed with pnpm workspaces.
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Build React package only
pnpm build:react
# Run demo site locally
pnpm demo:serve
Contributions are welcome! Here's how you can help:
main
pnpm build
and pnpm test
to ensure everything works# Clone the repository
git clone https://github.com/callum-gander/nine-slice-frame.git
cd nine-slice-frame
# Install dependencies
pnpm install
# Build all packages
pnpm build
# Run tests
pnpm test
# Type checking
pnpm typecheck
Found a bug or have a feature request? Please open an issue with:
MIT Ā© Callum Gander