SpreadSheet-Coding.com

PhpSpreadsheet

Add Strikethrough, Superscript And Subscript Text In Excel Files In PHP Using PHPSpreadSheet

Strikethrough, superscript and subscript all live on the same object – the cell’s Font – so they are one lesson rather than three. This article sets each of them, reads the file back to prove they survived the round trip, and shows why superscript and subscript can never both be on at once.

August 9, 2026

This article shows how to add strikethrough, superscript and subscript text in Excel files in PHP with the latest version of PhpSpreadsheet. All three live on the same object, the cell’s Font, so they are one lesson rather than three. A struck-through price marks an old value, while superscript and subscript carry the notation that plain text cannot — footnote markers, units, and chemical formulae.

The calls are short. First getStyle() selects the cell, then getFont() reaches its font, and finally setStrikethrough(), setSuperscript() or setSubscript() switches the effect on. Because these are font settings, each one applies to the entire cell.

That whole-cell scope is the thing to understand before you start. If you want part of a cell raised or struck — the 2 in x² but not the x — that is a different tool, and rich text inside a single cell is where it belongs. Below we style three cells, read the file back to confirm the settings stuck, and then look at a trap that catches people out: superscript and subscript cannot both be on.

Requirements to add strikethrough, superscript and subscript text:

Tested with PhpSpreadsheet 5.9 on PHP 8.5.

Step 1.

First, set up the dependencies. Here we pin the latest major release of PhpSpreadsheet (the 5.x line).

composer.json
{
    "require": {
        "phpoffice/phpspreadsheet": "^5.0"
    }
}

Step 2.

Next, install phpspreadsheet.

command line
$ composer install

Step 3.

Then create a new PHP file. Load Composer’s autoloader and import Spreadsheet, the Xlsx writer, and IOFactory for reading the file back at the end.

font-styles.php
<?php

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

Step 4.

Create the spreadsheet and lay down one row per effect. Column A names the style and column B carries the text that will show it.

font-styles.php
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->setTitle('Font');

$worksheet->fromArray([
    ['Style', 'Example'],
    ['Strikethrough', 'Was 49.99'],
    ['Superscript', 'x2'],
    ['Subscript', 'H2O'],
], null, 'A1');

Step 5.

Now apply the three effects. Each call reaches the same place — the cell’s font — and each one styles the whole cell, so x2 becomes a fully raised x2 rather than an x with a raised 2.

font-styles.php
// Each of these styles the WHOLE cell.
$worksheet->getStyle('B2')->getFont()->setStrikethrough(true);
$worksheet->getStyle('B3')->getFont()->setSuperscript(true);
$worksheet->getStyle('B4')->getFont()->setSubscript(true);

You can style a range the same way. For example, getStyle('B2:B10') strikes ten cells with one call, which is how you would grey out a block of cancelled orders.

Step 6.

Widen the columns so nothing clips, then save.

font-styles.php
$worksheet->getColumnDimension('A')->setAutoSize(true);
$worksheet->getColumnDimension('B')->setAutoSize(true);

(new Xlsx($spreadsheet))->save('font-styles.xlsx');
echo "Wrote font-styles.xlsx\n\n";

Step 7.

Finally, read the file back. Writing a style and having it survive the round trip are two different claims, so this loop checks all three effects on each cell and proves which one is actually set.

font-styles.php
$reloaded = IOFactory::load('font-styles.xlsx');
$sheet = $reloaded->getActiveSheet();

foreach (['B2' => 'Strikethrough', 'B3' => 'Superscript', 'B4' => 'Subscript'] as $cell => $label) {
    $font = $sheet->getStyle($cell)->getFont();
    printf(
        "%-4s %-14s strike=%-5s super=%-5s sub=%s\n",
        $cell,
        $label,
        var_export($font->getStrikethrough(), true),
        var_export($font->getSuperscript(), true),
        var_export($font->getSubscript(), true)
    );
}

Complete code to add strikethrough, superscript and subscript text.

font-styles.php
<?php

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->setTitle('Font');

$worksheet->fromArray([
    ['Style', 'Example'],
    ['Strikethrough', 'Was 49.99'],
    ['Superscript', 'x2'],
    ['Subscript', 'H2O'],
], null, 'A1');

// Each of these styles the WHOLE cell.
$worksheet->getStyle('B2')->getFont()->setStrikethrough(true);
$worksheet->getStyle('B3')->getFont()->setSuperscript(true);
$worksheet->getStyle('B4')->getFont()->setSubscript(true);

$worksheet->getColumnDimension('A')->setAutoSize(true);
$worksheet->getColumnDimension('B')->setAutoSize(true);

(new Xlsx($spreadsheet))->save('font-styles.xlsx');
echo "Wrote font-styles.xlsx\n\n";

// Read the file back to prove the styles survived the round trip.
$reloaded = IOFactory::load('font-styles.xlsx');
$sheet = $reloaded->getActiveSheet();

foreach (['B2' => 'Strikethrough', 'B3' => 'Superscript', 'B4' => 'Subscript'] as $cell => $label) {
    $font = $sheet->getStyle($cell)->getFont();
    printf(
        "%-4s %-14s strike=%-5s super=%-5s sub=%s\n",
        $cell,
        $label,
        var_export($font->getStrikethrough(), true),
        var_export($font->getSuperscript(), true),
        var_export($font->getSubscript(), true)
    );
}

Test adding strikethrough, superscript and subscript text.

Command line testing.

command line
$ php font-styles.php

Result of adding strikethrough, superscript and subscript text.

PhpSpreadsheet writes the file, and every effect reads back exactly where it was set. Notice that each row has precisely one true, which is what confirms the settings are independent of each other:

command line
Wrote font-styles.xlsx

B2   Strikethrough  strike=true  super=false sub=false
B3   Superscript    strike=false super=true  sub=false
B4   Subscript      strike=false super=false sub=true
Add strikethrough, superscript and subscript text: a terminal showing font-styles.xlsx written, then B2 reading back strike=true, B3 super=true and B4 sub=true, each row with exactly one setting true.

Open font-styles.xlsx in Excel and you can see the effects rather than merely read them back. Excel draws a line through the old price, and the other two cells sit raised and lowered against the baseline:

The font-styles.xlsx worksheet in Excel: cell B2 shows Was 49.99 struck through, B3 shows x2 raised as superscript, and B4 shows H2O lowered as subscript, beside their labels in column A.

Superscript and subscript cannot both be on.

Here is the trap. Excel stores the two as one setting with three states — raised, lowered, or neither — so they are mutually exclusive. Turning one on therefore turns the other off, silently and with no warning.

exclusive.php
<?php

require 'vendor/autoload.php';

use PhpOffice\PhpSpreadsheet\Spreadsheet;

$spreadsheet = new Spreadsheet();
$font = $spreadsheet->getActiveSheet()->getStyle('A1')->getFont();

$font->setSuperscript(true);
echo "after setSuperscript(true):\n";
echo '  superscript = ' . var_export($font->getSuperscript(), true) . "\n";
echo '  subscript   = ' . var_export($font->getSubscript(), true) . "\n";

$font->setSubscript(true);
echo "then setSubscript(true):\n";
echo '  superscript = ' . var_export($font->getSuperscript(), true) . "\n";
echo '  subscript   = ' . var_export($font->getSubscript(), true) . "\n";

Running it shows the second setting revoking the first:

command line
$ php exclusive.php
after setSuperscript(true):
  superscript = true
  subscript   = false
then setSubscript(true):
  superscript = false
  subscript   = true

So the last call wins. Strikethrough is different, because it is a separate flag — one cell can carry a strike and a superscript at once. Watch for this when a loop applies styles, or when a config array merges them, since two rules that each look correct can quietly cancel one another.

References for adding strikethrough, superscript and subscript text: