Created
October 10, 2025 23:48
-
-
Save soulwire/9ad9bf5b5340a19a58e5807332d5d31f to your computer and use it in GitHub Desktop.
SVG Nine Slice Border (React)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| interface SvgNineSliceBorderProps { | |
| // Source image URL | |
| imageUrl: string; | |
| // Source image width in pixels | |
| srcWidth: number; | |
| // Source image height in pixels | |
| srcHeight: number; | |
| // Slice markers in source pixels | |
| slices: [number, number, number, number]; | |
| // Border thickness in output units | |
| borderWidth: number; | |
| // Width in output units | |
| width: number; | |
| // Height in output units | |
| height: number; | |
| // Whether to fill the center region | |
| fill?: boolean; | |
| // X position in output units | |
| x?: number; | |
| // Y position in output units | |
| y?: number; | |
| } | |
| export function SvgNineSliceBorder({ | |
| imageUrl, | |
| srcWidth, | |
| srcHeight, | |
| slices, | |
| borderWidth, | |
| width, | |
| height, | |
| fill = false, | |
| x = 0, | |
| y = 0, | |
| }: SvgNineSliceBorderProps) { | |
| const [t, r, b, l] = slices; | |
| // Guard against pathological slices | |
| const midSrcW = Math.max(0, srcWidth - l - r); | |
| const midSrcH = Math.max(0, srcHeight - t - b); | |
| // Clamp border thickness to avoid overlaps | |
| const bwX = Math.min(borderWidth, Math.floor(width / 2)); | |
| const bwY = Math.min(borderWidth, Math.floor(height / 2)); | |
| const innerW = Math.max(0, width - 2 * bwX); | |
| const innerH = Math.max(0, height - 2 * bwY); | |
| return ( | |
| <g x={x} y={y}> | |
| {/* Corners */} | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={0} | |
| sy={0} | |
| sw={l} | |
| sh={t} | |
| x={0} | |
| y={0} | |
| width={bwX} | |
| height={bwY} | |
| /> | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={srcWidth - r} | |
| sy={0} | |
| sw={r} | |
| sh={t} | |
| x={width - bwX} | |
| y={0} | |
| width={bwX} | |
| height={bwY} | |
| /> | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={0} | |
| sy={srcHeight - b} | |
| sw={l} | |
| sh={b} | |
| x={0} | |
| y={height - bwY} | |
| width={bwX} | |
| height={bwY} | |
| /> | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={srcWidth - r} | |
| sy={srcHeight - b} | |
| sw={r} | |
| sh={b} | |
| x={width - bwX} | |
| y={height - bwY} | |
| width={bwX} | |
| height={bwY} | |
| /> | |
| {/* Edges */} | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={l} | |
| sy={0} | |
| sw={midSrcW} | |
| sh={t} | |
| x={bwX} | |
| y={0} | |
| width={innerW} | |
| height={bwY} | |
| /> | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={l} | |
| sy={srcHeight - b} | |
| sw={midSrcW} | |
| sh={b} | |
| x={bwX} | |
| y={height - bwY} | |
| width={innerW} | |
| height={bwY} | |
| /> | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={0} | |
| sy={t} | |
| sw={l} | |
| sh={midSrcH} | |
| x={0} | |
| y={bwY} | |
| width={bwX} | |
| height={innerH} | |
| /> | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={srcWidth - r} | |
| sy={t} | |
| sw={r} | |
| sh={midSrcH} | |
| x={width - bwX} | |
| y={bwY} | |
| width={bwX} | |
| height={innerH} | |
| /> | |
| {fill && ( | |
| <SvgNineSliceBorderTile | |
| imageUrl={imageUrl} | |
| srcWidth={srcWidth} | |
| srcHeight={srcHeight} | |
| sx={l} | |
| sy={t} | |
| sw={midSrcW} | |
| sh={midSrcH} | |
| x={bwX} | |
| y={bwY} | |
| width={innerW} | |
| height={innerH} | |
| /> | |
| )} | |
| </g> | |
| ); | |
| } | |
| interface SvgNineSliceBorderTileProps { | |
| // Source image URL | |
| imageUrl: string; | |
| // Source image width in pixels | |
| srcWidth: number; | |
| // Source image height in pixels | |
| srcHeight: number; | |
| // X position of the tile within the source image in pixels | |
| sx: number; | |
| // Y position of the tile within the source image in pixels | |
| sy: number; | |
| // Width of the tile within the source image in pixels | |
| sw: number; | |
| // Height of the tile within the source image in pixels | |
| sh: number; | |
| // X position of the tile in output units | |
| x: number; | |
| // Y position of the tile in output units | |
| y: number; | |
| // Width of the tile in output units | |
| width: number; | |
| // Height of the tile in output units | |
| height: number; | |
| } | |
| function SvgNineSliceBorderTile({ | |
| imageUrl, | |
| srcWidth, | |
| srcHeight, | |
| sx, | |
| sy, | |
| sw, | |
| sh, | |
| x, | |
| y, | |
| width, | |
| height, | |
| }: SvgNineSliceBorderTileProps) { | |
| return ( | |
| <svg | |
| x={x} | |
| y={y} | |
| width={width} | |
| height={height} | |
| viewBox={`${sx} ${sy} ${sw} ${sh}`} | |
| preserveAspectRatio="none" | |
| > | |
| <image href={imageUrl} width={srcWidth} height={srcHeight} preserveAspectRatio="none" /> | |
| </svg> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment