<div id="app"></div>
body {
  font-family: Trebuchet MS, sans-serif;
}
.download-link {
  color: black;
  text-decoration: none;
  background: white;
  padding: 1rem;
  border-radius: 5px;
  margin: 1rem;
  font-size: 2rem;
  box-shadow: 0 6px 6px rgba(0,0,0,.4)
}

.download {
  display: flex;
  flex-wrap: wrap;
  position: absolute;
  bottom: 2rem;
  left: 2rem;
}
const tartan = [
  { fill: "#FF8A00", size: 40 },
  { fill: "#E52E71", size: 10 },
  { fill: "#FFFFFF", size: 10 },
  { fill: "#E52E71", size: 70 },
  { fill: "#100e17", size: 20 },
  { fill: "#E52E71", size: 70 },
  { fill: "#FFFFFF", size: 10 },
  { fill: "#E52E71", size: 10 },
  { fill: "#FF8A00", size: 40 },
]

const SvgDefs = () => {
  return (
    <defs>
      <pattern
        id="diagonalStripes"
        x="0"
        y="0"
        width="8"
        height="8"
        patternUnits="userSpaceOnUse"
      >
        <polygon points="0,4 0,8 8,0 4,0" fill="#ffffff" />
        <polygon points="4,8 8,8 8,4" fill="#ffffff" />
      </pattern>
      <mask id="grating" x="0" y="0" width="1" height="1">
        <rect
          x="0"
          y="0"
          width="100%"
          height="100%"
          fill="url(#diagonalStripes)"
        />
      </mask>
    </defs>
  )
}

const SvgTile = ({ tartan }) => {
  
  const cumulativeSizes = tartan
    .map(el => el.size)
    .reduce(function(r, a) {
      if (r.length > 0) a += r[r.length - 1]
      r.push(a)
      return r
    }, [])

  const size = cumulativeSizes[cumulativeSizes.length - 1]
  return (
    <svg
      viewBox={`0 0 ${size} ${size}`}
      width={size}
      height={size}
      x="0"
      y="0"
      xmlns="http://www.w3.org/2000/svg"
    >
      <SvgDefs />
      <g id="horizStripes">
        {tartan.map((el, index) => {
          return (
            <rect
              fill={el.fill}
              height={el.size}
              width="100%"
              x="0"
              y={cumulativeSizes[index - 1] || 0}
            />
          )
        })}
      </g>
      <g id="vertStripes" mask="url(#grating)">
        {tartan.map((el, index) => {
          return (
            <rect
              fill={el.fill}
              height="100%"
              width={el.size}
              x={cumulativeSizes[index - 1] || 0}
              y="0"
            />
          )
        })}
      </g>
    </svg>
  )
}

const SvgBg = ({ svgData }) => {
  return (
    <div
        style={{
          width: "100%",
          height: "100vh",
          backgroundImage: `url("data:image/svg+xml;utf8,${svgData}")`,
        }}
      />
  )
}

const SvgDownloadLink = ({ svgData, fileName }) => {
  return (
    <a
      className="download-link"
      download={`${fileName}.svg`}
      href={`data:image/svg+xml;utf8,${svgData}`}
    >
      Download as SVG
    </a>
  )
}

const App = () => {
  const tartanStr = ReactDOMServer.renderToStaticMarkup(<SvgTile tartan={tartan} />)
  const tartanData = encodeURIComponent(tartanStr)
  return (
    <div className="App">
      <SvgBg svgData={tartanData} />
      <div className="download">
        <SvgDownloadLink svgData={tartanData} fileName="CSSTricks"/>
      </div>
    </div>
  )
}

const rootElement = document.getElementById("app")
ReactDOM.render(<App />, rootElement)
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom.production.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.11.0/umd/react-dom-server.browser.production.min.js