Themes & Styling

Everything you need to control the visual appearance of your charts: themes, colour palettes, series styling, data labels, and tooltips.


Built-in Themes

Apply a theme with .Theme(ChartTheme.X):

ChartBuilder.Create()
    .Theme(ChartTheme.Dark)
    // …
Theme Background Text Palette style Best for
ChartTheme.Default #ffffff white #333333 dark Blue-orange General use
ChartTheme.Dark #1a1a2e navy #f0f0ff light Neon-adjacent bright palette Browser dashboards
ChartTheme.Pastel #fafafa off-white #555555 grey Soft muted palette Presentations, reports
ChartTheme.Monochrome #ffffff white #000000 black Greyscale only Print, greyscale PDFs
ChartTheme.Ocean #0d1b2a deep navy #c8e6ff pale blue Blue-teal palette Analytics dashboards
ChartTheme.Sunset #1a0a2e purple-navy #ffe8c8 warm cream Vivid warm palette Editorial, marketing
ChartTheme.Forest #f6f4ee warm cream #2c2a1a earthy brown Earthy greens Nature / ESG reporting
ChartTheme.Neon #0a0a0a near-black #f0f0ff light Electric high-contrast palette Dark dashboards, streaming overlays
ChartTheme.Minimal #ffffff white #333333 graphite Muted professional palette Clean editorial reports
ChartTheme.Warm #faf3e0 parchment #3e2723 espresso Amber-brown earth tones Warm, print-style reports
ChartTheme.Arctic #f0f8ff ice blue #1c2e4a polar navy Cool crisp blues Clean corporate dashboards
ChartTheme.Business #ffffff white #333333 graphite Corporate blue-red palette Executive summaries
ChartTheme.Material #ffffff white #444444 charcoal Material Design 500-level palette Modern web dashboards
ChartTheme.TrafficLight #fafafa off-white #333333 graphite Green/amber/red status palette KPI / status dashboards
ChartTheme.Accessible #ffffff white #333333 graphite Colour-blind-safe (Wong 2011) Accessibility-critical charts
ChartTheme.Vivid #ffffff white #2c3e50 slate Full-spectrum distinct palette High-impact presentations
ChartTheme.HighContrast #ffffff white #000000 black WCAG AA (≥ 4.5:1) palette Accessibility-critical charts
ChartTheme.Modern #f8f8ff ghost white #2c3e50 slate Material palette + ModernStyle on Default recommendation for new dashboards

See Modern Styling below for what ModernStyle changes, and ChartColor Catalogue for the exact hex values behind each palette.

Dark Theme Example

string svg = ChartBuilder.Create()
    .Theme(ChartTheme.Dark)
    .Title("Server Throughput")
    .Size(700, 420)
    .XAxis("Hour", "00","04","08","12","16","20","24")
    .YAxis("Req/s", min: 0)
    .AsAnimated()
    .Series(s => s
        .AddArea("API",   new double[] { 820, 430, 1200, 1800, 1650, 1100, 640 })
        .AddLine("Cache", new double[] { 600, 310,  900, 1300, 1200,  850, 480 }))
    .RenderToSvg();

Output: Navy blue background (#1a1a2e), light axis labels, bright palette area/line. Grid lines rendered in muted #3a3a5e. Title text is #f0f0ff.

Pastel Theme Example

string svg = ChartBuilder.Create()
    .Theme(ChartTheme.Pastel)
    .Title("Monthly Sales")
    .Size(700, 420)
    .XAxis(x => x.Categories.AddRange(new[] { "Jan","Feb","Mar","Apr","May","Jun" }))
    .YAxis("Units", min: 0)
    .AsAnimated()
    .Series(s => s
        .AddColumn("Product A", new double[] { 420, 380, 510, 490, 560, 600 })
        .AddColumn("Product B", new double[] { 310, 290, 370, 400, 430, 450 }))
    .RenderToSvg();

Output: Off-white #fafafa background, very light grid lines, soft muted palette (#a8d8ea, #aa96da, …). Suitable for presentations and printed reports.


Modern Styling

Every built-in theme — including Default — has ChartTheme.ModernStyle set to true. It applies a consistent set of refinements uniformly across Static, Animated, and Interactive render modes:

  • Softly rounded corners on column/bar rectangles.
  • A subtle top-lighter fill gradient with soft elevation shadow on columns, bars, and areas.
  • Hollow-ring line/scatter markers instead of solid dots.
  • Crisper separators between pie/donut slices.
  • Fading (gradient) area-chart fills instead of a flat opacity.
  • Lighter, horizontal-only grid lines.
  • In Interactive mode only: a full-height/width hover band that highlights the entire category column or row on mouse-over, in addition to the point-level tooltip.

ChartTheme.Modern is a dedicated preset (Material palette on a ghost-white background) for teams that want the modern look front-and-centre, but the styling itself is not tied to that one preset — it is on by default for every theme above.

To opt out and get the classic flat look, clone a theme and turn it off:

var classic = ChartTheme.Dark.Clone();
classic.ModernStyle = false;

string svg = ChartBuilder.Create()
    .Theme(classic)
    .AsInteractive()
    .Series(s => s.AddColumn("Sales", new double[] { 420, 380, 510, 490 }))
    .RenderToSvg();

With ModernStyle = false, columns/bars render with sharp corners and a flat fill, markers render as solid dots, and hover bands are omitted from Interactive output.


Custom Theme

Create a one-off theme with ChartTheme.Custom(…):

var brandTheme = ChartTheme.Custom(
    backgroundColor:     "#0d1117",    // GitHub-dark background
    plotBackgroundColor: "none",
    gridLineColor:       "#21262d",
    axisLineColor:       "#30363d",
    textColor:           "#e6edf3",
    fontFamily:          "'Segoe UI', sans-serif",
    colors: new[] { "#58a6ff", "#3fb950", "#f78166", "#d29922", "#a371f7" }
);

string svg = ChartBuilder.Create()
    .Theme(brandTheme)
    .Title("Custom Brand Theme")
    .Size(700, 420)
    .XAxis("Quarter", "Q1","Q2","Q3","Q4")
    .YAxis("Revenue ($k)", min: 0)
    .AsAnimated()
    .Series(s => s
        .AddLine("Revenue", new double[] { 310, 420, 380, 510 })
        .AddLine("Target",  new double[] { 340, 400, 420, 500 }))
    .RenderToSvg();

Output: Dark background styled like GitHub’s dark mode. Blue and green lines are drawn against a near-black #0d1117 background with subtle grid lines.

ChartTheme.Custom parameters (all optional — unset properties fall back to Default):

Parameter Description
backgroundColor SVG/page background colour.
plotBackgroundColor Plot area fill. Use "none" for transparent.
gridLineColor Colour of horizontal grid lines.
axisLineColor Colour of axis border lines.
textColor Default text fill colour (title, labels, legend).
fontFamily CSS font-family for all text.
colors Ordered palette array — must have at least one entry when provided.

Overriding Palette Only

Use .Colors(…) to swap the palette without changing the rest of the active theme:

string svg = ChartBuilder.Create()
    .Theme(ChartTheme.Dark)                           // dark background + text
    .Colors(ChartColor.ChartRose, ChartColor.ChartYellow, ChartColor.ChartTeal)          // but use a custom 3-colour palette
    .Title("Sales Channels")
    .Size(700, 420)
    .XAxis("Month", "Jan","Feb","Mar","Apr","May","Jun")
    .YAxis("Units", min: 0)
    .AsAnimated()
    .Series(s => s
        .AddColumn("Online", new double[] { 180, 210, 190, 260, 310, 280 })
        .AddColumn("Store",  new double[] { 140, 160, 175, 200, 195, 220 })
        .AddLine("Total",    new double[] { 320, 370, 365, 460, 505, 500 }))
    .RenderToSvg();

Output: Dark theme background and text, but the three series use pink, yellow, and teal instead of the dark theme’s default palette.

Colours wrap: if you have 5 series and 3 colours, series 4 and 5 use colours 1 and 2 again.


ChartColor Catalogue

ChartColor (namespace TerraFluent.Chart.Reporting.Models) provides 400+ named colour constants as public const string values. Use them anywhere a colour string is accepted — no hex codes to remember.

using TerraFluent.Chart.Reporting.Models;

// Palette override
.Colors(ChartColor.ChartBlue, ChartColor.ChartOrange, ChartColor.ChartGreen)

// Per-series colour
.AddLine("Sales", data, cfg => cfg.Color(ChartColor.ChartRose))

// Plot annotation
.PlotLine(500, color: ChartColor.Red, width: 2, label: "SLA limit")

Chart Palette Constants

Constant Hex Default series slot
ChartColor.ChartBlue #7CB5EC 1st
ChartColor.ChartOrange #F7A35C 2nd
ChartColor.ChartGreen #90ED7D 3rd
ChartColor.ChartYellow #E4D354 4th
ChartColor.ChartIndigo #8085E9 5th
ChartColor.ChartRose #F15C80 6th
ChartColor.ChartTeal #2B908F 7th
ChartColor.ChartRed #F45B5B 8th
ChartColor.Charcoal #434348 Dark accent

Pastel Palette Constants

Constant Hex
ChartColor.PastelSkyBlue #A8D8EA
ChartColor.PastelPurple #AA96DA
ChartColor.PastelPink #FCBAD3
ChartColor.PastelMint #B5EAD7
ChartColor.PastelPeach #FFDAC1
ChartColor.PastelPeriwinkle #C7CEEA
ChartColor.PastelLime #E2F0CB
ChartColor.PastelLemon #FFFFD2

Pre-built Palettes

Apply a complete curated palette in one call:

.Colors(ChartColor.Palette.Default)      // Default palette (same as no override)
.Colors(ChartColor.Palette.Pastel)       // soft pastels — matches ChartTheme.Pastel
.Colors(ChartColor.Palette.Material)     // Material Design colours
.Colors(ChartColor.Palette.Business)     // professional blues / greys
.Colors(ChartColor.Palette.Accessible)   // WCAG high-contrast
.Colors(ChartColor.Palette.TrafficLight) // red / amber / green
.Colors(ChartColor.Palette.Monochrome)   // greyscale range

Colour Utility Methods

// Semi-transparent variant → "rgba(124,181,236,0.25)"
string faded   = ChartColor.WithOpacity(ChartColor.ChartBlue, 0.25);

// Tint / shade
string lighter = ChartColor.Lighten(ChartColor.ChartBlue, 0.20);
string darker  = ChartColor.Darken(ChartColor.ChartBlue, 0.20);

// From RGB components → "#7CB5EC"
string custom  = ChartColor.FromRgb(124, 181, 236);

// Blend two colours at equal weight
string mixed   = ChartColor.Mix(ChartColor.ChartBlue, ChartColor.White, 0.5);

The full catalogue (400+ constants: CSS named colours, web-safe primaries, chart palette, pastels, theme-specific tokens, and more) is defined in Models/ChartColor.cs.


Per-Series Colour

Override a single series colour inside the cfg => lambda:

.Series(s => s
    .AddLine("Revenue", data, cfg => cfg.Color(ChartColor.ChartBlue))
    .AddLine("Cost",    data, cfg => cfg.Color(ChartColor.ChartOrange))
    .AddLine("Profit",  data, cfg => cfg.Color(ChartColor.ChartGreen)))

Line Styling

.AddLine("Target", data, cfg => cfg
    .Color(ChartColor.ChartRose)
    .LineWidth(3)        // stroke width (px), default 2
    .Dashed()            // "Solid" | "Dashed" | "Dotted" | "DashDotted" | "LongDashed"
    .MarkerEnabled(false))

Dashed variants:

Method SVG stroke-dasharray Looks like
Solid() (none) ———————
Dashed() 8 4 - - - - - -
Dotted() 2 3 · · · · · ·
DashDotted() 8 4 2 4 -·-·-·-·-
LongDashed() 16 6 ——— ———

Example — dashed reference line on a line chart:

string svg = ChartBuilder.Create()
    .Title("Actuals vs Target")
    .Size(700, 400)
    .XAxis("Q", "Q1","Q2","Q3","Q4")
    .YAxis("Revenue ($k)", min: 0)
    .AsAnimated()
    .Series(s => s
        .AddColumn("Actuals", new double[] { 310, 390, 420, 510 },
            cfg => cfg.Color(ChartColor.ChartBlue))
        .AddLine("Target", new double[] { 300, 380, 420, 450 },
            cfg => cfg.Color(ChartColor.ChartRose).LineWidth(2).Dashed()))
    .RenderToSvg();

Output: Blue columns for actuals. A pink dashed horizontal reference line for the target. The dashes distinguish the target clearly without overwhelming the data.


Area Fill Opacity

.AddArea("Organic", data, cfg => cfg.Color(ChartColor.ChartBlue).FillOpacity(0.15))
.AddArea("Direct",  data, cfg => cfg.Color(ChartColor.ChartGreen).FillOpacity(0.40))
.AddArea("Paid",    data, cfg => cfg.Color(ChartColor.ChartOrange).FillOpacity(0.70))

FillOpacity accepts values from 0.0 (fully transparent) to 1.0 (fully opaque). Default is 0.25 for normal area, 0.7 for stacked area.

Output: Three overlapping area series, each at a different opacity. The Organic area at 15 % barely tints the background; the Paid area at 70 % is visually dominant.


Column / Bar Borders & Corner Radius

.AddColumn("Revenue", data, cfg => cfg
    .Color(ChartColor.ChartBlue)
    .BorderColor("#1a6090")    // contrasting outline
    .BorderWidth(1)            // border thickness (px)
    .BorderRadius(6))          // rounded top corners (px)

Example — three styled column series:

string svg = ChartBuilder.Create()
    .Title("Series Formatting — Border & Radius")
    .Size(760, 440)
    .XAxis("Q", "Q1","Q2","Q3","Q4")
    .YAxis("Value ($k)", min: 0)
    .AsAnimated()
    .Series(s => s
        .AddColumn("Revenue", new double[] { 320, 410, 390, 480 }, cfg => cfg
            .Color(ChartColor.ChartBlue).BorderColor("#1a6090").BorderWidth(1).BorderRadius(6))
        .AddColumn("Cost",    new double[] { 210, 260, 245, 290 }, cfg => cfg
            .Color(ChartColor.ChartOrange).BorderColor("#7a3a00").BorderWidth(2).BorderRadius(3))
        .AddColumn("Profit",  new double[] { 110, 150, 145, 190 }, cfg => cfg
            .Color(ChartColor.ChartGreen).BorderColor("#1e7a00").BorderWidth(2).BorderRadius(0)))
    .RenderToSvg();

Output: Three grouped column series. Revenue has rounded tops with a blue border; Cost has a dark orange border with subtle corners; Profit has a dark green thick border and sharp square corners.


Scatter Marker Styling

.AddScatter("Group A", data, cfg => cfg
    .Color(ChartColor.ChartBlue)          // dot fill
    .BorderColor("#e6b800")    // gold ring around dot
    .BorderWidth(2)            // ring thickness
    .MarkerSize(6))            // dot radius (px)

Output: Sky-blue dots with a gold ring border. Use this to differentiate overlapping points or to match corporate brand colours.


Data Labels

Show a value label on or near each data point.

// Enable on all series at once:
ChartBuilder.Create()
    .ShowDataLabels()
    .Series(s => s.AddColumn("Sales", data))

// Enable per-series with custom formatting:
.AddColumn("Budget", data, cfg => cfg
    .DataLabel
    .Show()
    .Format("${value}k")
    .Color("#1a6090")
    .FontSize(11)
    .Background("rgba(124,181,236,0.25)"))

DataLabelOptions quick reference:

Method Example Result
.Show() Enables labels
.Format("{value}%") 38% Value with suffix
.Format("${value}k") $320k Currency format
.Color(ChartColor.White) White text on coloured background
.FontSize(11) Smaller text for dense charts
.Background(ChartColor.ChartBlue) Solid pill background
.Background("rgba(…,0.25)") Tinted transparent pill
.Radius(1.25) Pie: label outside with connector
.OffsetY(-10) Nudge label 10 px upward

Three label styles on one chart:

string svg = ChartBuilder.Create()
    .Title("Data Label Showcase")
    .Size(760, 460)
    .XAxis("Quarter", "Q1","Q2","Q3","Q4")
    .YAxis("Value ($k)", min: 0)
    .AsAnimated()
    .Series(s => s
        // Style 1: solid pill — white text on series colour
        .AddLine("Revenue", new double[] { 310, 420, 385, 510 }, cfg =>
        {
            cfg.Color(ChartColor.ChartBlue).LineWidth(3);
            cfg.DataLabel.Show().Color("#fff").FontSize(11)
               .Background(ChartColor.ChartBlue).Format("${value}k");
        })
        // Style 2: tinted transparent background
        .AddColumn("Expenses", new double[] { 180, 210, 195, 240 }, cfg =>
        {
            cfg.Color(ChartColor.ChartOrange);
            cfg.DataLabel.Show().Color("#7a2f00").FontSize(10)
               .Background("rgba(247,163,92,0.3)").Format("${value}k");
        })
        // Style 3: no background, larger font
        .AddSpline("Profit", new double[] { 130, 210, 190, 270 }, cfg =>
        {
            cfg.Color(ChartColor.ChartGreen).LineWidth(2);
            cfg.DataLabel.Show().Color("#1a5e00").FontSize(13)
               .Format("+{value}k").Background("#cfffcf");
        }))
    .RenderToSvg();

Output: Revenue labels appear as solid blue pills. Expense column labels float above each bar with a light orange tint. Profit spline labels use a green-tinted background with larger text.


Pie / Donut Label Placement

Use DataLabel.Radius(fraction) to position slice labels:

Fraction Placement Connector
0.6 Inside the slice No
1.0 At the slice edge No
> 1.0 e.g. 1.25 Outside the pie Yes — spline connector
string svg = ChartBuilder.Create()
    .AsPie()
    .Title("Market Share")
    .Size(680, 480)
    .Labels("North America","Europe","Asia-Pacific","Lat. America","Rest of World")
    .Legend(l => l.AtBottom())
    .AsAnimated()
    .Series(s => s
        .Add("Share", new double[] { 38, 24, 20, 11, 7 }, cfg =>
            cfg.DataLabel.Show()
               .Radius(1.25)           // outside, with connector lines
               .Format("{value}%")
               .FontSize(11)
               .Color("#333333")
               .Background("rgba(255,255,255,0.85)")))
    .RenderToSvg();

Output: Each slice has a label outside the pie arc, connected to its slice by a thin curved spline line. Labels show “38%”, “24%”, etc. on a semi-transparent white pill.


Custom Tooltip Styling

string svg = ChartBuilder.Create()
    .Title("Tooltip — Dark Style")
    .Size(760, 440)
    .XAxis("Quarter", "Q1","Q2","Q3","Q4")
    .YAxis("USD ($k)", min: 0)
    .AsAnimated()
    .Tooltip(t => t
        .BackgroundColor("rgba(30,30,60,0.92)")
        .TextColor("#e8f4ff")
        .FontSize(12)
        .Border(ChartColor.ChartBlue, width: 1, radius: 6)
        .Padding(14)
        .Format("{label}: ${value}k")
        .TransitionDuration(0.20))
    .Series(s => s
        .AddLine("Revenue", new double[] { 320, 410, 390, 480 },
            cfg => cfg.Color(ChartColor.ChartBlue).LineWidth(3))
        .AddColumn("Cost", new double[] { 210, 260, 245, 290 },
            cfg => cfg.Color(ChartColor.ChartOrange)))
    .RenderToSvg();

Output (Interactive / Animated mode): When hovering a data point, a dark navy tooltip appears with a blue border, light text, and shows e.g. “Revenue: $410k”. It fades in over 200 ms.

Light tooltip without arrow:

.Tooltip(t => t
    .BackgroundColor("rgba(255,255,255,0.95)")
    .TextColor("#1a202c")
    .FontSize(11)
    .Border("#cbd5e0", width: 1, radius: 4)
    .Padding(12)
    .HideArrow()
    .Format("{label} — {value}k sessions"))

Output: White box with no triangular pointer, subtle grey border, dark text. Minimal and clean.


Legend Styling

// Vertical legend on the right side
.Legend(l => l
    .Vertical()
    .AlignRight()
    .AtMiddle()
    .Padding(12)
    .ItemFontSize(13)
    .ItemFontColor("#2d3748")
    .SymbolSize(14, 14)
    .SymbolRadius(7)             // fully circular swatch
    .Border("#cbd5e0", width: 1, radius: 6)
    .BackgroundColor("rgba(255,255,255,0.92)"))

// Horizontal legend at the top
.Legend(l => l
    .AtTop()
    .AlignCenter()
    .Horizontal()
    .Padding(8)
    .ItemFontSize(12)
    .Border("#4a5568", width: 1, radius: 4)
    .BackgroundColor("rgba(255,255,255,0.85)"))

Output (vertical right): A bordered legend box floats on the right side of the chart with circular coloured swatches and slightly larger font than the default.

Output (top center): A horizontal legend bar sits above the plot area with a subtle border, centred.

View this page's source on GitHub →