JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://d3js.org/d3.v4.min.js"></script>
<div>

</div>

CSS

text {
  fill: white;
}

    .axis path,
    .axis line {
      fill: none;
      stroke: #000;
      shape-rendering: crispEdges;
    }
    
    .x.axis path {
      display: none;
    }
    
    .line {
      fill: none;
      stroke: steelblue;
      stroke-width: 1.5px;
    }

/* tell the SVG path to be a thin blue line without any area fill */

path.line {
  stroke: #00AEEF;
  stroke-width: 4;
  fill: none;
  &.bad {
    stroke: #EE227B;
  }
}

.overlay {
  fill: none;
  pointer-events: all;
}

path.domain {
  stroke: none;
}

.tick {
  line {
    stroke: none;
  }
}

.area {
  fill: url(#area-gradient);
  stroke-width: 0;
  &.bad {
    fill: url(#bad-area-gradient);
  }
}

circle {
  fill: #D8D8D8;
  stroke: #000;
  stroke-width: 1;
}

.chart-value-inspector {
  border: solid 1px #d8d8d8;
}

JavaScript

function drawEndPoint(svg, point) {
  svg.append('circle')
    .attr('class', 'endpoint')
    .attr('cx', point.x)
    .attr('cy', point.y)
    .attr('r', '5');
}


function computeArea(xScale, yScale, bottom, yVariable) {
  return d3.area()
    .x(d => xScale(d.x))
    .y0(bottom)
    .y1(d => yScale(d[yVariable]))
}

function drawArea(svg, data, computedArea, className = '') {
  return svg.append('path')
    .datum(data)
    .attr('class', 'area ' + className)
    .attr('d', computedArea);
}

function computeLine(xScale, yScale, yVariable) {
  return d3.line()
    .x(d => xScale(d.x))
    .y(d => yScale(d[yVariable]))
}

function drawLine(svg, data, computedLine, className) {
  return svg.append('path')
    .datum(data)
    .attr('class', className)
    .attr('d', computedLine);
}

function drawXAxisHelper(svg, xScale, xExtent, height, tickFormat) {
  let xAxisLabel = svg.append('g')
    .attr('transform', 'translate(0,' + height + ')')
    .call(d3.axisBottom(xScale)
      .tickValues(xExtent)
      .tickFormat(d => tickFormat(d)));

  // Align all text to the end
  xAxisLabel.selectAll('text')
    .style('text-anchor', 'end');

  // Align the first text element to the start
  xAxisLabel.select('text')
    .style('text-anchor', 'start');
}

function drawXAxisWithAge(svg, xScale, xExtent, height, baseAge) {
  drawXAxisHelper(svg, xScale, xExtent, height, d => {
    let year = new Date().getFullYear();
    return `${year + d - 1} - (Age ${baseAge + d - 1})`;
  });
}

function drawXAxis(svg, xScale, xExtent, height) {
  drawXAxisHelper(svg, xScale, xExtent, height, d => d);
}

function drawVerticalGradient(svg, id, bottomColor, topColor) {
  return svg.append('linearGradient')
    .attr('id', id)
    .attr('x1', '100%')
    .attr('y1', '100%')
    .attr('x2', '100%')
    .attr('y2', '0%')
    .attr('spreadMethod', 'pad')
    .selectAll('stop')
    .data([{
      offset: '0%',
      color: bottomColor
    }, {
      offset: '100%',
      color: topColor
    }])
  ...