Nine Patch React

Nine Patch React provides a simple React component, <NinePatch>, that you can use to put any content inside a box rendered from an image using the "nine-patch" technique. This technique allows you to create a scalable box with unique borders and corners from a base image.

Contents

  1. How it works
  2. Installation and usage
  3. Showcase
  4. Properties

How it works

Nine Patch React provides a simple React component, <NinePatch>, that you can use to put any content inside a box rendered from an image using the "nine patch" or "nine slice" technique. This technique allows you to create a scalable box with unique borders and corners from a base image.
Example strip
Read more on the technique onWikipedia: 9-slice scaling.

Installation and usage

To install simply run the following command in your project directory:
npm install --save @stur86/nine-patch-react
And you can use it simply like this:

simple.tsx

import NinePatch from "@stur86/nine-patch-react";
...
<NinePatch src='your_frame.png'>
Content here!
</NinePatch>

Showcase

Here is an example of a simple pixel art frame:
Cobalt frame
You can use it to create a text box, like this:
Hello, world!

Simple text box

<NinePatch
pixelPerfect
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAVJJREFUeJzt1DFKQ0EYRtFR32qyCVOmdx2BLMd12Nqk84GNGEhj5wJSpxC00+gCPMW7p/thig8uzNXz28fnCPHy+jimMca439/oLYt0PqzGtR6xdNPlcT68qx2Lsb49jvm0+b6nvw+eHu7+ddDS7LbzmPc/d18QVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqATZfH+vY4dttZbVmkXwHm02bMe7RkofqCsOnl9XGcDyu9Y7G+APIdH+Uu5EMgAAAAAElFTkSuQmCC"
>
<span className="pixel-text">
Hello, world!
</span>
</NinePatch>
The text box size is controlled by its contents and the container it's in. For example:
Hello, world!

Smaller text box

<div
style={{
maxWidth: '500px'
}}
>
<NinePatch
pixelPerfect
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAVJJREFUeJzt1DFKQ0EYRtFR32qyCVOmdx2BLMd12Nqk84GNGEhj5wJSpxC00+gCPMW7p/thig8uzNXz28fnCPHy+jimMca439/oLYt0PqzGtR6xdNPlcT68qx2Lsb49jvm0+b6nvw+eHu7+ddDS7LbzmPc/d18QVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqATZfH+vY4dttZbVmkXwHm02bMe7RkofqCsOnl9XGcDyu9Y7G+APIdH+Uu5EMgAAAAAElFTkSuQmCC"
>
<span className="pixel-text">
Hello, world!
</span>
</NinePatch>
</div>
The border variables control how much of the frame is considered to constitute the "border" of the frame. Since the content is only inserted in the central cell of the nine patches, the border will also behave as a sort of padding. In order for the frame to visualize correctly the important thing is that the border here includes the actual edge, which is only 4 pixels wide. This gives us some leeway. Normally the border is set to 33% of the image size. It can be expressed in pixels or as a percentage of the image size. We can make it smaller to get a tighter fit:
Hello, world!

Compact text box

<div
style={{
maxWidth: '500px'
}}
>
<NinePatch
borderBottom="16px"
borderLeft="16px"
borderRight="16px"
borderTop="16px"
pixelPerfect
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAVJJREFUeJzt1DFKQ0EYRtFR32qyCVOmdx2BLMd12Nqk84GNGEhj5wJSpxC00+gCPMW7p/thig8uzNXz28fnCPHy+jimMca439/oLYt0PqzGtR6xdNPlcT68qx2Lsb49jvm0+b6nvw+eHu7+ddDS7LbzmPc/d18QVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqATZfH+vY4dttZbVmkXwHm02bMe7RkofqCsOnl9XGcDyu9Y7G+APIdH+Uu5EMgAAAAAElFTkSuQmCC"
>
<span className="pixel-text">
Hello, world!
</span>
</NinePatch>
</div>
We can also use the scale option to make the image bigger and get a proper "pixel art" look. It's important to use the pixelPerfect option to get the best result and avoid unwanted smoothing. Here's an example:
Hello, world!

Thicker text box

<div
style={{
maxWidth: '500px'
}}
>
<NinePatch
borderBottom="6px"
borderLeft="6px"
borderRight="6px"
borderTop="6px"
pixelPerfect
scale={3}
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAVJJREFUeJzt1DFKQ0EYRtFR32qyCVOmdx2BLMd12Nqk84GNGEhj5wJSpxC00+gCPMW7p/thig8uzNXz28fnCPHy+jimMca439/oLYt0PqzGtR6xdNPlcT68qx2Lsb49jvm0+b6nvw+eHu7+ddDS7LbzmPc/d18QVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqATZfH+vY4dttZbVmkXwHm02bMe7RkofqCsOnl9XGcDyu9Y7G+APIdH+Uu5EMgAAAAAElFTkSuQmCC"
>
<span className="pixel-text">
Hello, world!
</span>
</NinePatch>
</div>
And of course, you can also use this to work with regular art. In that case you won't need the pixelPerfect option.
Bubblegum frame
Hello, world!

Cute text box

<NinePatch
borderBottom="20%"
borderLeft="30%"
borderRight="30%"
borderTop="20%"
scale={0.6}
src="https://stur86.github.io/nine-patch-react/assets/bubblegum-DQBnp-Zo.png"
>
<span className="cute-text">
Hello, world!
</span>
</NinePatch>
You can put more than just basic text inside a frame, of course. Here's an example with an image:
The Holy Grail

Grail box

<div
style={{
height: '300px',
width: '300px'
}}
>
<NinePatch
pixelPerfect
scale={2}
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAWFJREFUeJzt1KFNbGEURtEDGUsHz42EvKBo4PVCCSg8HTxDF+NGTAM3IaGBCUUgEaAQzHiWuHvJo77cnftffLw9f06IZbefSz1irZbdfmZmNt+Hp8f/bMwa/bvbzsz0B2ib08PL67vYsQoP97dzWI4/bmcBZmb+Xv35lUFrc32zPQvQE4QVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwAWAGwAmAFwAqAFQArAFYArABYAbACYAXACoAVACsAVgCsAFgBsAJgBcAKgBUAKwBWAKwA2Ob08HB/O9c3W7Fllc4CHJbjHJaj2LJKPUHYxcfb8+ey2+sdq3XZx7e+AGN1Ij0Djv0aAAAAAElFTkSuQmCC"
>
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'center'
}}
>
<img
alt="The Holy Grail"
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAQZJREFUWIXtlsENwjAMRR+oqAemoJQTbMAarMCZWdiDNdgATgW24IBUCQ7IIq2axGkpFdB/qeJE8Ytjx4Ve/66BbWK/Xd0B8iwmmt0Kc3Vsy82u0tfQRZdnceHb1BYMIPTmyZrYqmS9Anhew3wxdW7g0jhJARhN1lY/zgh8Qp0DRNqFx8MZALkSGYvKdhlfLyfnvt4IlB29W84khPqJqElAUOZAm1HwAtheMI18p1cBiEKiIOHXSAUgUQiB0JweFEloShoUvMrMlDbxagOYIGWAcZIGORZ1/hL2AJ0DBCeNWQlVCn24vi8C0JfhjwEE9wLbz4nZAVvpBb5GVBdCtchX+yZQKMQDDMhmDx1q3/sAAAAASUVORK5CYII="
style={{
height: '128px'
}}
/>
</div>
</NinePatch>
</div>
Or some code
console.log("Hello, world!");

Code box

<NinePatch
pixelPerfect
scale={2}
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAbxJREFUeJzt3aFuwlAYQOG/C8EjsAjEEh5mGsszzEw2SAzPgJ3ew5BMILAIPIaJ7RLuDcmWXMYh5XyqhJLe/IfSJhU08aPtj49pe37YNKGruzTjJ245iohozqtMR/t43w7I9XReOeNTgOlon+04mQ3rjvTyWff5e/PxXPXx9WqXvU4RPANurJxxL10MsgvE6xuwtO5rl4vT9sWLcPXPjn5Vzti7IJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaA5QG69hjxHhUz9gyAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAJgBYAaAGQBmAFgeoPKvmvQHxYw9A2AGgBkAZgCYAWAGgBkAZgCYAWAGgBkAZgCYAWAGgBkAlgVYr3bUOh5GOeNe2x8fy53a5eJmC3pUae5N2piO9tkOk9mw7ghd+0emyqeF5Tf/fTuIiLMAEd8R0hv6H+WMm7RxHmJ+2DShq7s0Y++CYF/V4lM4M57WYgAAAABJRU5ErkJggg=="
>
<pre
style={{
backgroundColor: 'rgba(0, 10, 30, 0.6)'
}}
>
console.log("Hello, world!");
</pre>
</NinePatch>

Properties

PropertyTypeDescription
srcstringPath to the image to use as a frame.
scalenumber (Optional)Scale factor for the image. Default is 1.
pixelPerfectboolean (Optional)Whether to use pixel-perfect scaling. Default is false.
borderTopstring (Optional)Size of the top border. Can be in pixels or percentage. Default is 33%.
borderRightstring (Optional)Size of the right border. Can be in pixels or percentage. Default is 33%.
borderBottomstring (Optional)Size of the bottom border. Can be in pixels or percentage. Default is 33%.
borderLeftstring (Optional)Size of the left border. Can be in pixels or percentage. Default is 33%.