Skip to main content

We have released KoliBri - Public UI v3. For the LTS version, see .

Your opinion matters! Together with you, we want to continuously improve KoliBri. Share your ideas, wishes, or suggestions—quickly and easily.

Using CSS Custom Properties Safely in Themes

· 2 minutes of reading time
Martin Oppitz
Architekt@ITZBund & Creator of KoliBri
ChatGPT
AI companion - Answering questions, sparking conversations, helping.

KoliBri, also known as Public UI Components, relies on adaptive styles to enable flexible theming. CSS custom properties provide a convenient way to control colors, spacing and other design values. However, the Shadow DOM does not shield them: custom properties cascade globally and may collide with variables on the host page.

Problem

Extensive use of custom properties in a theme increases the risk of name clashes with root-level variables. Such conflicts can unexpectedly change the appearance of an application and confuse both users and developers.

Strategies to Avoid Collisions

  • Use namespaces: Prefixes like --kolibri- lower the chance of overlapping variable names, yet they are no absolute guarantee.
  • Map internal values to SCSS: Calculations and intermediate values should rely on SASS variables ($variable). They are resolved at build time and do not appear as global custom properties.
  • Expose only what is necessary: Keep the set of external custom properties as small as possible to minimize collision risks.

Checklist

  1. Start from design tokens: Use the prefixed tokens defined in Figma as your foundation.
  2. Switch to SCSS variables: Replace internal custom properties with SASS variables to keep computations encapsulated.
  3. Update documentation: Clearly state which properties are public and which remain internal.

Conclusion

By combining SCSS with a minimal set of custom properties, themes stay maintainable and collision-free. Following these guidelines results in robust designs that integrate smoothly into any host environment.

ButtonLink vs. LinkButton – What matters for assistivity?

· 2 minutes of reading time
Martin Oppitz
Architekt@ITZBund & Creator of KoliBri
ChatGPT
AI companion - Answering questions, sparking conversations, helping.

Building accessible components often confronts us with small details that have a bigger impact than expected. A recent example from the KoliBri project raises the question: how should our hybrid components ButtonLink and LinkButton be announced by screen readers?


The debate

There are two possible approaches:

1. By design – "It is announced as it looks."

  • A ButtonLink that looks like a link is announced as a link.
  • A LinkButton that looks like a button is announced as a button.

Pro: Consistency – links sound alike, buttons sound alike. Con: Behavior and expectation may diverge.

2. By behavior – "It is announced as it acts."

  • A ButtonLink that performs an action in the current context is announced as a button.
  • A LinkButton that triggers navigation is announced as a link.

Pro: Meets expectations – users know whether they are activating or navigating. Con: The visual cue might not match the audible cue.


The decision

After discussion from design and accessibility perspectives, the conclusion was clear:

Expectation outweighs appearance.

Screen-reader users rely on links to navigate and buttons to perform actions. Even when the visual style differs, alignment between behavior and announcement is more important.


Why does this matter?

  • Accessibility means reliability. Users shouldn't have to guess whether a "link" changes the page or just submits a form.
  • Design can mislead; behavior cannot. A button that looks like a link is still an action. A link that looks like a button is still navigation.
  • Consistency builds trust. Clarity is essential, especially for screen reader announcements.

Conclusion

The decision in the KoliBri project is:

  • ButtonLink is announced as a button.
  • LinkButton is announced as a link.

This choice emphasizes expected behavior and strengthens assistivity for all users.


ComponentLooks like …Behaves like
ButtonLinkLinkButton
LinkButtonButtonLink

Components Package, Themes and Peer Dependencies

· 2 minutes of reading time
Martin Oppitz
Architekt@ITZBund & Creator of KoliBri

Our project uses several NPM packages that work together to build reusable interfaces. The core is the components package. It delivers the Web Components with their functionality but without fixed styling. This keeps each component lean and allows it to fit into different design concepts.

Headless components

The components are intentionally built in a headless way. They contain no defaults for colors, spacing or fonts. This freedom allows every organization to define the look completely on its own and seamlessly embed the components into existing design systems.

Themes provide the styling

The visual appearance is added via separate theme packages. A theme describes the design of buttons, form fields or tables—it delivers the visual look. Users of the components can write their own theme and combine the same functionality with an individual interface.

Peer dependencies ensure version compatibility

To make clear which theme version matches which components version, we rely on peer dependencies. In a theme package the peer dependency specifies the version range of the components package for which the theme is intended. We follow a simple rule: one theme version belongs exactly to one components version.

Installation and checks

During npm install, NPM automatically verifies whether the peer dependencies are satisfied. If the versions do not match, an error message appears. This hint is intentional, because it prevents installing a combination that could cause problems later.

No legacy mode

NPM offers the legacy peer deps option to skip this verification. In our setup this mode must not be used. Without the error messages it is easy to end up with wrong or broken installations.

Summary

  • Components package: provides the functional building blocks without styling.
  • Theme package: provides the appearance.
  • Peer dependencies: ensure both fit together exactly.
  • NPM error messages: desired and important.