Custom CSS on SharePoint Online sites

Custom CSS on SharePoint Online sites

We’ll be using SharePoint Online as platform for our upcoming intranet. As Microsoft currently doesn’t support much visual tweaking, we were looking to apply our own CSS to the intranet related SPO sites.

Applying Custom CSS is not supported, so we were looking for a workaround until Microsoft hopefully does enable this in the future.

Although not supported, and likely not even recommended, we got our custom CSS up and running by creating an application customizer, based on the official docs, and installing this on our sites.

In order to apply CSS to all parts of the site on which the app is installed on, we used the approach described on this SO post. For example, to adjust the hub navigation entry, you can do something like this in your SCSS file:

@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';

:global {
    .ms-HubNav-nameLink {
        font-size: 30px;
        font-weight: 500;
        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif

For reference, something like this application code might suffice for setting your custom CSS:

import {
} from '@microsoft/decorators';
import {
} from '@microsoft/sp-core-library';
import {
} from '@microsoft/sp-application-base';
import {
} from '@microsoft/sp-dialog';
import styles from './AppCustomizer.module.scss';
import {
} from '@microsoft/sp-lodash-subset';

import * as strings from 'AcmeThemeApplicationCustomizerStrings';

const LOG_SOURCE: string = 'AcmeThemeApplicationCustomizer';
export interface IAcmeThemeApplicationCustomizerProperties {
  Top: string;
  Bottom: string;

export default class AcmeThemeApplicationCustomizer
extends BaseApplicationCustomizer < IAcmeThemeApplicationCustomizerProperties > {
  private _topPlaceholder: PlaceholderContent | undefined;
  private _bottomPlaceholder: PlaceholderContent | undefined;

  public onInit(): Promise < void > {, `Initialized ${strings.Title}`);

    let message: string =;
    if (!message) {
      message = '(No properties were provided.)';

    this.context.placeholderProvider.changedEvent.add(this, this._renderPlaceHolders);
    return Promise.resolve();

  private _renderPlaceHolders(): void {

    // Handling the top placeholder
    if (!this._topPlaceholder) {
      this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(
        PlaceholderName.Top, {
          onDispose: this._onDispose

      // The extension should not assume that the expected placeholder is available.
      if (!this._topPlaceholder) {
        console.error("The expected placeholder (Top) was not found.");

      if (this._topPlaceholder.domElement) {
        this._topPlaceholder.domElement.innerHTML = `
        <div class="${}">
        <div class="${}">
        <strong>Here you can create your own, custom "header"</strong>

private _onDispose(): void {
  console.log('[HelloWorldApplicationCustomizer._onDispose] Disposed custom top and bottom placeholders.');

Actually, I believe a lot of the above code is redundant, but I haven’t had the change to check it out yet.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: