KISS Component System

Auflistung der fertiggestellten Basis-Komponenten des Contao-KISS-Frameworks.

1. Colors

Light

Brand

primary
secondary
accent

Base

base-100
base-200
base-300
base-content

Semantic

info
success
warning
error

Brand

primary
secondary
accent

Base

base-100
base-200
base-300
base-content

Semantic

info
success
warning
error

2. Typography

Type System

  • Font: FFMarkPro (--font-sans) — Regular 400, Bold 700, plus a Bold Italic used for display headings
  • h1 / h2: italic + uppercase display (~104px / ~50px). h3–h6: regular case
  • Helpers: .h1.h6 apply heading sizes to any element; .topline for eyebrow text
  • Hero: wrap an h1 in .h1-xxl for the oversized hero headline (up to 190px)
  • Scale tokens: --text-base--text-5xl and --text-8xl (see Type Scale)

Font Family

--font-sans: "FFMarkPro", system-ui, sans-serif

The quick brown fox jumps over the lazy dog

The quick brown fox

ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 0123456789 & ? ! @ # %

Heading Hierarchy

Rendered with the .h1.h6 helpers. Sizes are responsive (mobile → md breakpoint).

.h1 · text-5xl → md:text-8xl · italic · uppercase · ~104px

Headline

.h2 · text-4xl → md:text-5xl · italic · uppercase · ~50px

Headline

.h3 · text-2xl → md:text-4xl

The quick brown fox jumps over the lazy dog

.h4 · text-xl → md:text-2xl

The quick brown fox jumps over the lazy dog

.h5 · text-lg → md:text-xl

The quick brown fox jumps over the lazy dog

.h6 · text-base → md:text-lg

The quick brown fox jumps over the lazy dog

.topline · text-lg → md:text-xl · bold

Eyebrow / Topline

Type Scale

The explicitly defined --text-* tokens for this brand.

Class Size Sample
text-base1.125rem · 18pxSample text
text-lg1.5rem · 24pxSample text
text-xl1.75rem · 28pxSample text
text-2xl2.125rem · 34pxSample text
text-3xl2.25rem · 36pxSample text
text-4xl2.5rem · 40pxSample text
text-5xl3.125rem · 50pxSample text
text-8xl6.5rem · 104pxSample text

Weights & Styles

FFMarkPro ships Regular (400), Bold (700) and a Bold Italic (display). Other weights are synthesised by the browser — avoid relying on them.

font-normal · 400 Aa Bb Cc
font-bold · 700 Aa Bb Cc
italic font-bold · display Aa Bb Cc

Body & Rich Text

How running copy renders inside .rte (the rich-text wrapper).

Topline

Body copy uses text-base (1.125rem). Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt. This is a link, some bold text and some italic text for contrast.

A blockquote is set larger (text-xl → md:text-3xl) to stand out from the surrounding copy.
  • First list item
  • Second list item

3. Button Component

Component Structure

.btn + [style] + [color] + [size] + [shape] + [shadow] + [state]
  • Styles: (default/solid), btn-soft, btn-outline, btn-text
  • Colors: btn-primary, btn-secondary, btn-accent, btn-info, btn-success, btn-warning, btn-error
  • Sizes: btn-xs, btn-sm, (default), btn-lg, btn-xl
  • Shapes: (default/rounded), btn-circle, btn-square, btn-wide, btn-block
  • Shadows: btn-shadow-none, btn-shadow-sm, btn-shadow-md, btn-shadow-lg
  • States: btn-active, disabled

Example: <button class="btn btn-primary btn-lg btn-shadow-md">Save</button>

Style & Color Variants

Styles modify how colors are displayed. Combine: .btn + .btn-[style] + .btn-[color]

Style Default Primary Secondary Accent Info Success Warning Error
Solid
(default)
Soft
.btn-soft
Outline
.btn-outline
Text
.btn-text

Size Variants

.btn-xs
0.75rem
.btn-sm
0.875rem
.btn
1rem
.btn-lg
1.125rem
.btn-xl
1.25rem

Shape Variants

.btn-circle
.btn-square
.btn-wide

Circle and square buttons scale with size variants (always 1:1 ratio):

xs
sm
md
lg
xl
xs
sm
md
lg
xl
.btn-block

Shadow Variants

Shadows grow on hover, shrink on active.

.btn-shadow-none
.btn-shadow-sm
.btn-shadow-md
.btn-shadow-lg

Button States

Default state
.btn-active
disabled

4. Badge Component

Component Structure

.badge + [style] + [color] + [size] + [shape]
  • Styles: (default/solid), badge-soft, badge-outline, badge-dashed
  • Colors: badge-primary, badge-secondary, badge-accent, badge-info, badge-success, badge-warning, badge-error
  • Sizes: badge-xs, badge-sm, (default), badge-lg, badge-xl
  • Shapes: (default/rounded), badge-pill, badge-square

Example: <span class="badge badge-success badge-soft badge-lg">Active</span>

Style & Color Variants

Styles modify how colors are displayed. Combine: .badge + .badge-[style] + .badge-[color]

Style Default Primary Secondary Accent Info Success Warning Error
Solid
(default)
Solid Solid Solid Solid Solid Solid Solid Solid
Soft
.badge-soft
Soft Soft Soft Soft Soft Soft Soft Soft
Outline
.badge-outline
Outline Outline Outline Outline Outline Outline Outline Outline
Dashed
.badge-dashed
Dashed Dashed Dashed Dashed Dashed Dashed Dashed Dashed

Size Variants

XS
.badge-xs
0.625rem
Small
.badge-sm
0.75rem
Default
.badge
0.875rem
Large
.badge-lg
1rem
Extra Large
.badge-xl
1.125rem

Shape Variants

Default
Rounded corners
Pill Shape
.badge-pill
Square
.badge-square

5. Link Component

Component Structure

.link + [color] + [size] + [underline-style] + [special]
  • Colors: link-primary, link-secondary, link-accent, link-info, link-success, link-warning, link-error
  • Sizes: link-xs, link-sm, (default), link-lg, link-xl
  • Underline: (default/always), link-underline-hover, link-underline-animate, link-underline-none
  • Special: link-external, link-disabled

Example: <a class="link link-primary link-underline-animate">Hover me</a>

Style & Color Variants

Links appear at 80% opacity by default, full intensity on hover. Combine: .link + .link-[style] + .link-[color]

Style Default Primary Secondary Accent Info Success Warning Error
Default
(default)
Default Default Default Default Default Default Default Default
Hover
.link-underline-hover
Hover Hover Hover Hover Hover Hover Hover Hover
Animate
.link-underline-animate
Animate Animate Animate Animate Animate Animate Animate Animate
None
.link-underline-none
None None None None None None None None

Size Variants

Extra Small
.link-xs
0.75rem
Small
.link-sm
0.875rem
Default
.link
1rem
Large
.link-lg
1.125rem
Extra Large
.link-xl
1.25rem

Special Variants

External Link
.link-external
Shows external icon
Disabled Link
.link-disabled
Non-interactive

6. Card Component

Component Structure

.card + [size] + [style] + [color] + [interactive]
  • Sizes: card-xs, card-sm, (default), card-lg, card-xl
  • Styles: (default/solid), card-soft, card-outline, card-glass
  • Colors: card-primary, card-secondary, card-accent, card-info, card-success, card-warning, card-error
  • Interactive: card-hover, card-grow, card-link
  • Layout: card-side, image-full
  • Sections: card-header, card-body, card-footer, card-title, card-actions

Card Structure

Body Only

Simplest card with just card-body.

With Header

Card-header adds a top section with border.

Full Structure

Header, body, and footer sections.

Size Variants

XS
.card-xs
Small
.card-sm
Default
.card
Large
.card-lg
Extra Large
.card-xl

Color & Style Variants

Styles modify how colors are displayed. Combine: .card-[style] .card-[color]

Style Default Primary Secondary Accent Info Success Warning Error
Solid
(default)
Solid
Solid
Solid
Solid
Solid
Solid
Solid
Solid
Soft
.card-soft
Soft
Soft
Soft
Soft
Soft
Soft
Soft
Soft
Outline
.card-outline
Outline
Outline
Outline
Outline
Outline
Outline
Outline
Outline

Glass Style .card-glass

Default
Primary
Success
Error

Interactive Variants

Add hover/focus effects. Can combine with any style/color.

Hover Shadow

Adds shadow on hover.

.card-hover
Grow

Scales up on hover.

.card-grow
Link Card

Clickable with pointer cursor. Combine with hover/grow for effects.

.card-link

Combined Example

Layout Variants

Side Layout .card-side

product
Horizontal Card

Image on side with card-side class.

product
With Soft Style

Side layout + soft primary.

Image Full Overlay .image-full

overlay
Image Overlay

Content overlays the background image.

Card with Actions

Actions in Body

Buttons at the bottom of card-body.

Actions in Header

Toolbar-style layout with actions in header.

7. Alert Component

Component Structure

.alert + [style] + [color]
  • Styles: (default/solid), alert-soft, alert-outline, alert-dashed
  • Colors: alert-primary, alert-secondary, alert-accent, alert-info, alert-success, alert-warning, alert-error
  • Sections: alert-icon, alert-content, alert-title, alert-description

Example: <div class="alert alert-success alert-soft">...</div>

Alert Structure

Alerts support different content layouts using alert-icon, alert-title, and alert-description.

Simple (content only)
This is a simple alert with just content text.
.alert > .alert-content
With Icon
This alert includes an icon for better visual recognition.
.alert > .alert-icon + .alert-content > .alert-description
With Title and Description
Success!
Your changes have been saved successfully.
.alert-content > .alert-title + .alert-description
Full Structure (Icon + Title + Description)
Warning: Action Required
Please review your settings before continuing. Some configurations may need your attention.
.alert > .alert-icon + .alert-content > (.alert-title + .alert-description)

Color & Style Variants

Styles modify how colors are displayed. Combine: .alert + .alert-[style] + .alert-[color]

Color Solid Soft Outline Dashed
Default
.alert
Solid
Soft
Outline
Dashed
Primary
.alert-primary
Solid
Soft
Outline
Dashed
Secondary
.alert-secondary
Solid
Soft
Outline
Dashed
Accent
.alert-accent
Solid
Soft
Outline
Dashed
Info
.alert-info
Solid
Soft
Outline
Dashed
Success
.alert-success
Solid
Soft
Outline
Dashed
Warning
.alert-warning
Solid
Soft
Outline
Dashed
Error
.alert-error
Solid
Soft
Outline
Dashed

8. Pagination Component

Component Structure

.pagination + [size] + [shape]
  • Sizes: pagination-xs, pagination-sm, (default), pagination-lg, pagination-xl
  • Shapes: (default/rounded), pagination-circle, pagination-square

Note: Pagination items inherit button styles through CSS. Inactive = default button, Active (strong) = primary button.

Default Pagination

Size Variants

Shape Variants

With Icons

Disabled State

9. Breadcrumb Component

JS Configuration (Stimulus)

data-controller="breadcrumb"
  • Targets: data-breadcrumb-target="list|item"
  • Max Items: data-breadcrumb-max-items-value="5" (collapse when MORE than N marked items)

How it works: Only items with data-breadcrumb-target="item" are counted and collapsible. When collapsed, ALL marked items are hidden and shown in a dropdown. Items without the attribute stay always visible.

CSS Classes

.breadcrumb + [size] + [color]
  • Sizes: breadcrumb-xs, breadcrumb-sm, (default), breadcrumb-lg, breadcrumb-xl
  • Colors: breadcrumb-primary, breadcrumb-secondary, breadcrumb-accent, etc. (changes hover color)
  • Separators: .breadcrumb-separator (use SVG icons or text characters)

Contao: .mod_breadcrumb inherits all styles. Add variant classes via CSS ID field.

Dropdown: Size and color variants apply to the generated dropdown menu as well.

Default (Responsive Collapse)

This example has 4 marked items ≤ default max of 5, so it's expanded on desktop. On screens <640px, the CSS variable --breadcrumb-force-collapse: 1 triggers collapse.
Note: The collapse state is determined on page load. It does NOT auto-collapse when resizing the browser window.

Color Variants (Collapsed)

All examples use max-items="3" to force collapse (4 marked items > 3). Hover over links and ellipsis to see color.

Size Variants (Collapsed)

All examples use max-items="3" to force collapse. Click the ellipsis to see dropdown sizing.

10. Popover & Dropdown Component

JS Configuration (Stimulus)

data-controller="popover"
  • Targets: data-popover-target="trigger|content|arrow"
  • Placement: data-popover-placement-value="top|bottom|left|right" (default: bottom)
  • Alignment: data-popover-alignment-value="start|center|end" (default: center)
  • Trigger: data-popover-trigger-value="click|hover" (default: click)
  • Flip: data-popover-flip-value="true|false" (default: true)
  • Actions: click->popover#toggle, click->popover#close

CSS Classes

.popover-content + [size] + [preset]
  • Sizes: popover-xs, popover-sm, (default), popover-lg, popover-xl
  • Presets: popover-dropdown, popover-tooltip
  • Arrow: .popover-arrow (optional, auto-positioned)
  • Menu: .dropdown-menu, .dropdown-item, .dropdown-separator, .dropdown-label
  • Item states: .dropdown-item.active, [aria-disabled="true"]

Placement Variants

Set placement with data-popover-placement-value. Click trigger requires data-action="click->popover#toggle"

Placement: top
placement="top"
Placement: bottom
placement="bottom"
Placement: left
placement="left"
Placement: right
placement="right"

Trigger Variants

Set trigger with data-popover-trigger-value. Hover works automatically, click needs action.

Click triggered
trigger="click" (default)
Hover triggered
trigger="hover"

Alignment Variants

Set alignment with data-popover-alignment-value. Aligns popover along placement axis.

Aligned to start
alignment="start"
Aligned to center
alignment="center" (default)
Aligned to end
alignment="end"

Size Variants

Add size class to .popover-content

Extra small
.popover-xs
Small popover
.popover-sm
Default size popover
(default)
Large popover
.popover-lg
Extra large popover
.popover-xl

Size Variants with Hover (Tooltip Style)

Same sizes but with data-popover-trigger-value="hover" and .popover-tooltip

Extra small tooltip
.popover-xs
Small tooltip
.popover-sm
Default size tooltip
(default)
Large tooltip
.popover-lg
Extra large tooltip
.popover-xl

Preset Variants

Presets apply predefined styling. Add to .popover-content

Default style
(default)
.popover-dropdown
Tooltip style
.popover-tooltip

Dropdown Menu

Use .popover-dropdown with .dropdown-menu, .dropdown-item, .dropdown-separator, .dropdown-label

Interactive Content

Popovers can contain forms and buttons. Use data-action="click->popover#close" for close buttons.

Dimensions

Set the dimensions for the layer.

Delete this item?

This action cannot be undone.

11. Input Component

Component Structure

.form-input + [style] + [color] + [size]
  • Styles: (default/outline), input-soft
  • Colors: input-primary, input-secondary, input-accent, input-info, input-success, input-warning, input-error
  • Sizes: input-xs, input-sm, (default), input-lg, input-xl
  • States: is-valid, is-invalid, disabled, readonly
  • Labels: label-text, helper-text, error-text, success-text

Example: <input class="form-input input-primary" placeholder="Enter text">

Input Structure

Inputs support labels, helper text, and error messages.

With Label & Helper
We'll never share your email
.label-text + .form-input + .helper-text
Required Field
.label-text.label-required
Valid State
Username is available
.form-input.is-valid + .success-text
Invalid State
Password must be at least 8 characters
.form-input.is-invalid + .error-text

Color & Style Variants

Colors apply to focus state. Combine: .form-input + .input-[style] + .input-[color]

Color Outline (default) Soft
Default
Primary
.input-primary
Secondary
.input-secondary
Accent
.input-accent
Info
.input-info
Success
.input-success
Warning
.input-warning
Error
.input-error

Size Variants

.input-xs
.input-sm
.form-input
.input-lg
.input-xl

Floating Label

Label floats up when input is focused or has value.

.input-floating > .form-input + .input-floating-label
With Placeholder Text

When using a placeholder with floating label, placeholder shows only when input is focused.

placeholder="you@example.com"
Floating Label Limitations
  • Background matching: The floating label needs a solid background to "sit on" the input border. By default, it uses bg-base-100. Add a matching bg-* class to .input-floating when on different backgrounds.
  • Supported backgrounds: Only full color classes work: bg-base-{100|200|300}, bg-{primary|secondary|accent|neutral|info|success|warning|error}. Opacity variants like bg-primary/10 are not supported.
  • Soft style not recommended: When using .input-soft, the input has a tinted background while the label has a solid background, creating visible contrast. Use outline style inputs with floating labels.
  • Background consistency: For the best appearance, ensure the background color inside the input (transparent for outline style) matches the background color of the container.
✗ Avoid this:

Input with Icons

Use .input-group wrapper with .has-icon-left or .has-icon-right.

Leading Icon
.input-group.has-icon-left
Trailing Icon
.input-group.has-icon-right
Both Icons
.has-icon-left.has-icon-right

Input States

Disabled
disabled attribute
Readonly
readonly attribute
With Value

12. Input Number

Number input with increment/decrement buttons. Layout is determined by HTML order. Requires input-number Stimulus controller.

Default (Number Left, Buttons Right)

HTML order: input → button − → button +

<div class="input-number">
<input type="number" class="form-input" ...>
<button class="input-number-btn">−</button>
<button class="input-number-btn">+</button>
</div>

Center (− Number +)

HTML order: button − → input → button + with .input-number-center

<div class="input-number input-number-center">
<button class="input-number-btn">−</button>
<input type="number" class="form-input" ...>
<button class="input-number-btn">+</button>
</div>

Layout & Style Variants

Combine layout (.input-number / .input-number-center), style (.input-soft), and color classes. Buttons inherit colors automatically.

Layout Default Primary Secondary Accent Info Success Warning Error
Default
.input-number
Center
.input-number-center
Soft
.input-soft
Soft Center
.input-soft
.input-[color] → buttons inherit automatically

Size Variants

Buttons scale automatically based on the input size class.

.input-xs
.input-sm
.form-input (default)
.input-lg
.input-xl

Min, Max & Step

The controller respects min, max, and step attributes. Buttons are disabled when limits are reached.

min=0, max=10
step=5
step=0.5 (decimals)

Disabled State

disabled attribute on input and buttons

13. Textarea Component

Component Structure

.form-textarea + [style] + [color] + [size]
  • Styles: (default/outline), textarea-soft
  • Colors: textarea-primary, textarea-secondary, textarea-accent, textarea-info, textarea-success, textarea-warning, textarea-error
  • Sizes: textarea-xs, textarea-sm, (default), textarea-lg, textarea-xl
  • Resize: (default/vertical), textarea-resize-none, textarea-resize-x, textarea-resize-both
  • States: is-valid, is-invalid, disabled, readonly

Example: <textarea class="form-textarea textarea-primary" placeholder="Enter message"></textarea>

Textarea Structure

Textareas follow the same patterns as inputs.

With Label & Helper
Maximum 500 characters
.label-text + .form-textarea + .helper-text
Invalid State
Description is required
.form-textarea.is-invalid + .error-text

Color & Style Variants

Colors apply to focus state. Combine: .form-textarea + .textarea-[style] + .textarea-[color]

Default (Outline)
Solid
Primary
Success

Size Variants

.textarea-xs
.textarea-sm
.form-textarea
.textarea-lg
.textarea-xl

Floating Label

.textarea-floating > .form-textarea + .textarea-floating-label

Resize Options

default (resize-y)
.resize-none
.resize-x
.resize-both

14. Select Component

Component Structure

.form-select + [style] + [color] + [size]
  • Styles: (default/outline), select-soft
  • Colors: select-primary, select-secondary, select-accent, select-info, select-success, select-warning, select-error
  • Sizes: select-xs, select-sm, (default), select-lg, select-xl
  • States: is-valid, is-invalid, disabled

Example: <select class="form-select select-primary">...</select>

Select Structure

Selects follow the same patterns as inputs.

With Label & Helper
Select your preferred category
.label-text + .form-select + .helper-text
Invalid State
Please select a country
.select.is-invalid + .error-text

Color & Style Variants

Colors apply to focus state. Combine: .form-select + .select-[style] + .select-[color]

Style Default Primary Secondary Accent Info Success Warning Error
Outline
(default)
Soft
.select-soft

Size Variants

.select-xs
.select-sm
.select
.select-lg
.select-xl

Floating Label

Unlike inputs, select floating labels remain floated at all times.

.select-floating > .form-select + .select-floating-label

With Leading Icon

Selects only support leading icons (trailing is the dropdown arrow).

.select-group.has-icon-left

Option Groups

<optgroup label="...">

Validation States

Selection confirmed
.select.is-valid
Please make a selection
.select.is-invalid

Disabled State

disabled

15. Checkbox Component

Component Structure

.form-checkbox + [color] + [size]
  • Colors: checkbox-primary, checkbox-secondary, checkbox-accent, checkbox-info, checkbox-success, checkbox-warning, checkbox-error
  • Sizes: checkbox-xs, checkbox-sm, (default), checkbox-lg, checkbox-xl
  • States: disabled, indeterminate (via JS)

Example: <input type="checkbox" class="form-checkbox checkbox-primary">

Default Checkbox

<input type="checkbox" class="form-checkbox">

Colors

.checkbox-primary, .checkbox-secondary, etc.

Sizes

.checkbox-xs, .checkbox-sm, .checkbox-lg, .checkbox-xl

Disabled State

disabled

Indeterminate State

The indeterminate state is set via JavaScript. It shows a horizontal line instead of a checkmark.

element.indeterminate = true;

16. Radio Component

Component Structure

.form-radio + [color] + [size]
  • Colors: radio-primary, radio-secondary, radio-accent, radio-info, radio-success, radio-warning, radio-error
  • Sizes: radio-xs, radio-sm, (default), radio-lg, radio-xl
  • States: disabled

Example: <input type="radio" name="group" class="form-radio radio-primary">

Default Radio

<input type="radio" name="group" class="form-radio">

Colors

.radio-primary, .radio-secondary, etc.

Sizes

.radio-xs, .radio-sm, .radio-lg, .radio-xl

Disabled State

disabled

17. Switch Component

Component Structure

.form-switch + [color] + [size] + [variant]
  • Colors: switch-primary, switch-secondary, switch-accent, switch-info, switch-success, switch-warning, switch-error
  • Sizes: switch-xs, switch-sm, (default), switch-lg, switch-xl
  • Variants: switch-outline
  • States: disabled

Example: <input type="checkbox" class="form-switch switch-primary">

Default Switch

.form-switch

Colors

.switch-primary, .switch-secondary, .switch-accent, etc.

Sizes

.switch-xs, .switch-sm, .switch-lg, .switch-xl

Outline Variant

.switch-outline

Disabled State

disabled

18. Range Component

Component Structure

.form-range + [color] + [size]
  • Colors: range-primary, range-secondary, range-accent, range-info, range-success, range-warning, range-error
  • Sizes: range-xs, range-sm, (default), range-lg, range-xl
  • States: disabled

Example: <input type="range" class="form-range range-primary" min="0" max="100" value="50">

Default Range

<input type="range" class="form-range">

Colors

Default
Primary
Secondary
Accent
Info
Success
Warning
Error
.range-primary, .range-secondary, .range-accent, etc.

Sizes

XS
.range-xs
SM
.range-sm
Default
.range
LG
.range-lg
XL
.range-xl

Min, Max & Step

0 Range: 0-10 10
0 Step: 25 100
min="0" max="10" step="25"

Disabled State

disabled

With JavaScript (Stimulus Controller)

The range component can be enhanced with the range Stimulus controller for:

  • Fill effect: Track fills with color as you drag (add .range-fill)
  • Value display: Live value updates in a target element

How to use

  1. 1. Add data-controller="range" to a wrapper element
  2. 2. Add data-range-target="input" to the range input
  3. 3. Add data-action="input->range#update" to trigger updates
  4. 4. (Optional) Add .range-fill class for fill effect
  5. 5. (Optional) Add data-range-target="value" to an element to display the value
  6. 6. (Optional) Add data-range-suffix-value="%" to add a suffix

Fill Variant

Add .range-fill to show a colored fill up to the thumb position.

.form-range.range-fill + data-controller="range" + data-range-target="input" + data-action="input->range#update"

Value Display

Add data-range-target="value" to any element to display the current value. Use data-range-suffix-value to add a suffix like "%". The fill effect (.range-fill) is optional.

22
Value display only
75
Value display + fill effect
data-range-target="value" — fill is optional (add .range-fill if desired)

Full Example

50
10 GB 100 GB
<div data-controller="range" data-range-suffix-value=" GB">
<span data-range-target="value">50</span>
<input type="range" class="form-range range-fill range-primary"
       data-range-target="input"
       data-action="input->range#update"
       min="10" max="100" step="10" value="50">
</div>

19. Theme Controller

Animated Sun/Moon Toggle

The easiest way to add a theme toggle. Just include the Twig template - no additional setup required. It automatically connects to the theme controller.

Default (24px)

Medium (32px)

Large (48px)

Usage

{# Default size (24px) #}
{{ include('@Contao/kiss_component/theme/_toggle.html.twig') }}

{# Custom size #}
{{ include('@Contao/kiss_component/theme/_toggle.html.twig', { size: 32 }) }}

{# With additional classes #}
{{ include('@Contao/kiss_component/theme/_toggle.html.twig', { class: 'my-class' }) }}

🎨 Animation Features

  • Sun rays: Scale down and fade out when transitioning to moon
  • Moon mask: Slides in to create crescent shape
  • Rotation: -45° tilt in dark mode
  • Hover: Playful wiggle animation
  • Easing: Spring-like cubic-bezier for organic motion

Theme Controller (Stimulus)

The underlying Stimulus controller that powers all theme switching. Use this to create custom toggle implementations.

Controller Reference

data-controller="theme"
  • Modes: light, dark, system (follows OS preference)
  • Methods: toggle() switches light↔dark, set() sets specific mode
  • Targets: toggle, radio, select, lightIcon, darkIcon
  • Events: Dispatches theme:change with detail { mode, theme, isDark }
  • Storage: Persists to localStorage automatically
  • Sync: Multiple controllers on the same page stay in sync

Toggle Variants (Light ↔ Dark)

Simple two-way toggles for switching between light and dark mode.

Switch Toggle

<label data-controller="theme">
<input type="checkbox" class="switch"
 data-theme-target="toggle"
 data-action="change->theme#toggle">
</label>

Checkbox Toggle

Same pattern, just use .checkbox instead

Button with Text

<div data-controller="theme">
<button class="btn" data-action="click->theme#toggle">
<span data-theme-target="lightIcon">Light Mode</span>
<span style="display: none;" data-theme-target="darkIcon">Dark Mode</span>
</button>
</div>

Mode Selectors (Light / Dark / System)

Three-way selectors that include "System" mode which follows the OS preference. All selectors use data-action="change->theme#set" to call the set() method which reads the value from the input.

Dropdown Select

Native select element. The controller auto-syncs the selected option on page load.

<div data-controller="theme">
<select class="select select-primary"
  data-theme-target="select"
  data-action="change->theme#set">
<option value="light">Light</option>
<option value="dark">Dark</option>
<option value="system">System</option>
</select>
</div>

Radio Buttons

Standard visible radios. Use .radio class for styling and any color variant.

Each radio input needs data-theme-target="radio" and data-action="change->theme#set". The controller automatically checks the correct radio on page load based on the stored preference.

Segmented Control

Hidden radios with custom styling. Uses .sr-only to hide inputs and peer-checked: to style the visible span when selected.

The .sr-only class hides the radio visually while keeping it accessible. The peer class on the input allows sibling elements to react to its state using peer-checked: variants. This pattern works with any Tailwind utility.

Pill Buttons

Hidden radios styled as buttons. Uses .btn classes with peer-checked: to apply active state styling.

Same technique as the segmented control but using .btn classes instead. The !bg-primary with important modifier ensures the background color applies correctly when combined with other button styles.

Events

Listen for theme changes anywhere in your application:

document.addEventListener('theme:change', (event) => {
console.log('Theme changed:', event.detail);
// { mode: 'dark', theme: 'dark', isDark: true }
});

KISS Component System - Phase 1

All components ready for production use