> For the complete documentation index, see [llms.txt](https://playground.e107sk.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://playground.e107sk.com/plugin-dev-quick-notes/how-to/rendering-a-plugin-page-without-the-site-themes-css.md).

# Rendering a plugin page without the site theme's CSS

Applies to: e107 v2.3+ Verified against: e107\_core/templates/header\_default.php, e107\_handlers/js\_manager.php

### The problem

You have a plugin page that ships its own front-end framework — an admin-like dashboard, a member area, a booking screen — and it has to look the same on every site that installs the plugin.

`e_IFRAME` gets you part of the way: it suppresses the theme's HEADER and FOOTER markup, so your page is no longer wrapped in the site's layout. But the page still **loads every stylesheet the theme registered**, because e107 builds one `<head>` for the whole request and has no notion of "this page is not themed".

The result is a page that looks right on one theme and broken on the next: your framework and the theme's Bootstrap both style `.table`, `.btn` and `.card`, and which one wins depends on the theme the site happens to run.

Writing CSS overrides against that is a losing game. You cannot know which theme you are fighting, and every override you add to win one argument breaks a different site.

***

### The mechanism

CSS is not emitted file by file. e107 sorts every registered stylesheet into one of six **zones**, and `header_default.php` renders the zones in the order named by the `CSSORDER` constant:

```php
// e107_core/templates/header_default.php
$CSSORDER = deftrue('CSSORDER')
    ? explode(",", CSSORDER)
    : array('library', 'other', 'core', 'plugin', 'theme', 'inline');

foreach($CSSORDER as $val)
{
    $cssId = $val . "_css";
    $e_js->renderJs($cssId, false, 'css');
}
```

Two things follow from those seven lines, and the second one is the useful one:

1. **The order of the zones is configurable** — which is how a plugin makes its stylesheet win over the theme's.
2. **A zone that is not in the list is never rendered at all.**

Nothing else reads `CSSORDER`. Leaving a zone out does not disable the API that fills it; the files are still registered; they are simply never written to the page.

#### The zones, and what puts a file in each

| Zone      | Filled by                                          | Typically holds                                           |
| --------- | -------------------------------------------------- | --------------------------------------------------------- |
| `library` | `$e_js->registerLibrary()`, theme `<libraries>`    | jQuery UI, Bootstrap, framework CSS declared by the theme |
| `other`   | `e107::css('url', ...)`, `$e_js->otherCSS()`       | CDN links, preview theme, backward-compatibility files    |
| `core`    | `$e_js->coreCSS()`                                 | `e107.css` — the admin bar, message boxes                 |
| `plugin`  | `e107::css('myplugin', ...)`, `$e_js->pluginCSS()` | **your plugin's stylesheets**                             |
| `theme`   | `$e_js->themeCSS()`, `THEME_STYLE`                 | the site theme's `style.css` and anything it registers    |
| `inline`  | `$e_js->inlineCSS()`                               | `<style>` blocks                                          |

***

### The fix

Define `CSSORDER` in your plugin's front controller, before anything renders, and leave out the zones you do not want:

```php
<?php

if(!defined('e107_INIT'))
{
    require_once(__DIR__.'/../../../class2.php');
}

// Only these zones are rendered. The site theme's stylesheet and everything
// the theme declares as a library never reach this page.
define('CSSORDER', 'other,core,plugin,inline');

// ... register your own CSS, then:
require_once(HEADERF);
```

`e107::css('myplugin', 'assets/css/mystyle.css')` puts your file in the `plugin` zone, which is still listed, so it renders as usual.

#### Where the definition has to sit

`CSSORDER` is read while `header_default.php` builds the `<head>`, so it must be defined **before `HEADERF` is required**. Anywhere after `class2.php` and before the header is fine. Defined later, it is simply ignored — and the symptom is a page that looks exactly as if you had never touched it.

#### Dropping core CSS as well

`e107.css` is in the `core` zone, but it has its own switch rather than being dropped from `CSSORDER` — it is registered conditionally:

```php
// header_default.php
if(!(isset($no_core_css) && $no_core_css !== true) && defset('CORE_CSS') !== false)
{
    $e_js->otherCSS('{e_WEB_CSS}e107.css');
}
```

So:

```php
define('CORE_CSS', false);
```

Think twice about this one. `e107.css` styles the admin bar and e107's message boxes; without it a logged-in administrator loses the bar and your `{ALERTS}` come out unstyled.

***

### Use it with `e_IFRAME`, not instead of it

The two solve different halves of the same problem, and you normally want both:

```php
define('CSSORDER', 'other,core,plugin,inline');   // no theme stylesheets
define('e_IFRAME', true);                          // no theme HEADER/FOOTER markup
```

`e_IFRAME` also adds `class='e-iframe'` to the body and lets the theme opt back in through `e_IFRAME_HEADER` / `e_IFRAME_FOOTER`, so a theme that wants to wrap iframe pages still can.

***

### Checking it worked

View source and look at the `<link rel="stylesheet">` tags. You should see your plugin's files and nothing from `e107_themes/`.

If a theme stylesheet is still there, it was not in the `theme` zone. The two usual reasons:

* the theme registers its CSS with `$e_js->otherCSS()` or a CDN URL, which lands in `other` — drop `other` from the list as well;
* the theme declares it in `theme.xml` as a `<library>`, which lands in `library` — that zone is already out of the example above.

Work from the rendered `<head>`: the order of the tags mirrors the order of the zones, so you can tell which zone a file came from by where it appears.

***

### Why not just override the CSS

Because an override cannot know what it is overriding.

The specific trap: a framework like Tabler and the theme's Bootstrap both style through CSS custom properties. Load order settles a conflict between two rules setting the **same property**, but a variable set by the theme keeps applying no matter which stylesheet wins the rule — `background-image` from the theme survives a later `background-color` from your framework, because they are different properties.

Not rendering the theme's CSS removes the argument instead of trying to win it, and it is the only approach that behaves the same on a theme you have never seen.

***

### Summary

| Goal                              | Line                                                            |
| --------------------------------- | --------------------------------------------------------------- |
| No theme stylesheets              | `define('CSSORDER', 'other,core,plugin,inline');`               |
| Also no `e107.css`                | `define('CORE_CSS', false);`                                    |
| No theme HEADER/FOOTER markup     | `define('e_IFRAME', true);`                                     |
| Your CSS last (keeping the theme) | `define('CSSORDER', 'library,other,core,theme,plugin,inline');` |

All of them must be defined before `HEADERF` is required.
