Skip to content

Theming

The formatter's output is the ai_disclosure theme hook, which renders the ai_disclosure:ai-disclosure single-directory component, and its look is a small set of CSS custom properties, not hard-coded values. This page covers the essentials. The class tree and custom properties carries the full tree for both the disclosure and the report, with every custom property and copy-paste examples.

Custom properties

Set them on both selectors, .ai-disclosure-wrapper, .ai-disclosure. Custom properties inherit downwards only, and the card draws its border on the wrapper, which is the ancestor of .ai-disclosure: a value set on .ai-disclosure alone never reaches it.

Every rule reads them with a fallback, so a theme overrides what it needs and leaves the rest. A rule in the theme's own CSS is enough. The module's stylesheet stays untouched.

Property Default Effect
--ai-disclosure-gap 0.75em Space between the icon and the text in the header
--ai-disclosure-icon-height 2em The icon's rendered height (width follows, the icons are not square)
--ai-disclosure-border-width 1px Width of the card border and the details divider
--ai-disclosure-border-color rgb(128, 128, 128, 0.35) Color of the card border and the details divider
--ai-disclosure-border-radius 4px Corner radius of the card
--ai-disclosure-padding 1em 1.25em Inner padding of the card
--ai-disclosure-sentence-weight 700 Font weight of the disclosure sentence, card style only
--ai-disclosure-secondary-size 0.9em Font size of the legal line, the editorial responsibility line and the statement link, card style only
--ai-disclosure-secondary-opacity 0.75 Opacity of the legal line, the editorial responsibility line and the statement link, card style only
--ai-disclosure-divider-gap 0.75em Space above and below the divider between the details section and the header, card style only

Example, changing only the border color from a theme:

.ai-disclosure-wrapper,
.ai-disclosure {
  --ai-disclosure-border-color: rgb(20, 60, 120, 0.4);
}

The reference marks each class in the disclosure's markup as legal, structure or decoration. The icon, the disclosure sentence and the notice line are the disclosure itself. A theme that removes them drops the disclosure. The card wrapper, the details section and the statement link are presentation and safe to restyle or remove.

Replacing the stylesheet

The formatter always attaches the module's own CSS. A theme can replace it with its own using libraries-override in its .info.yml, a mechanism of Drupal itself, not a setting of this module:

libraries-override:
  ai_disclosure/disclosure:
    css:
      component:
        css/ai-disclosure.css: css/my-theme-ai-disclosure.css

Overriding the template

The markup lives in components/ai-disclosure/ai-disclosure.twig, and templates/ai-disclosure.html.twig is the theme hook's thin wrapper around it. A theme overrides the wrapper the usual Drupal way, by copying it into its own templates/ directory, and gets the whole markup: the override replaces the wrapper, so it can embed the component with different props or print its own markup instead. Theme suggestions target a specific grade or entity type without a preprocess hook:

  • ai-disclosure--[grade-id].html.twig, e.g. ai-disclosure--ai-deepfake.html.twig
  • ai-disclosure--[entity-type].html.twig, e.g. ai-disclosure--media.html.twig

Suggestions are a theme hook feature with no equivalent in a component: a theme overrides a component wholesale, not per suggestion. That is why the theme hook stays.

Placing the component

The same markup is available wherever the disclosure is not a field on the entity being rendered: an assembled page, a block, a listing. From a template:

{{ include('ai_disclosure:ai-disclosure', {
  sentence: 'This image was generated with AI.',
  label_requirement: 'required',
}) }}

From code:

$build['disclosure'] = [
  '#type' => 'component',
  '#component' => 'ai_disclosure:ai-disclosure',
  '#props' => [
    'sentence' => $this->t('This image was generated with AI.'),
    'label_requirement' => 'required',
  ],
  '#slots' => [
    'description' => ['#markup' => $description],
  ],
];

sentence is the only required prop. Everything the formatter works out on its own, the visibility policy, the effective grade and the icon variant, is the caller's to decide here.

The report

The compliance report is plain Views output. Its exposed form has no template and no theme hook of this module's own, the same as core's own admin views, so the admin theme lays it out. The module adds one class of its own, ai-disclosure-report__notices, on the "Configuration notices" details above the table, and one rule for it in css/ai-disclosure-report.css, the report library. There are no --ai-disclosure-report-* custom properties. The reference lists that class and says what the exposed form, the header and the footer each leave to the theme.