UIX supports different ways of styling your application, including:
- Global CSS: Simple to use and familiar for those experienced with traditional CSS.
- CSS Modules: Create locally scoped CSS classes for your class components to improve maintainability.
- Tailwind CSS: A utility-first CSS framework that allows for rapid custom designs by composing utility classes.
- Inline CSS: Embed CSS directly in your JSX components, enabling dynamic and scoped styling.
- Element-scoped CSS: Allows for having CSS styles bound to single JSX elements, enabling element-scoped styling.
- Reactive CSS: Allows for creating CSS Stylesheets with reactive properties.
- Sass (deprecated): A popular CSS preprocessor that extends CSS with features like variables, nested rules, and mixins.
You can define general global styles in an entrypoint.css
file next to the entrypoint.ts
file for backend or frontend.
Note
Although SCSS is supported natively by UIX, we recommend using CSS files rather than SCSS files. Modern CSS already includes most of the features that are provided by SCSS. For this reason, CSS support will be completely removed from UIX in future versions.
To apply CSS styles to a component in a module, you can create a CSS file next to the module file (e.g. MyComponent.tsx
) sharing the same base name (e.g. MyComponent.css
).
The styles declared in the CSS file are automatically applied to all instances of the component and are not exposed to other components.
You can use the :host
selector to access the component root element (also when not using a Shadow DOM).
@template(<p>Hello, UIX!</p>)
class MyComponent extends Component {
// ...
}
:host {
color: red;
font-size: large;
p {
margin: 10px;
}
}
If you need to apply styles to elements outside of a component, you can use global stylesheets.
Another way to add CSS rules to a component is to use inline styles with the @style
decorator:
@style(css `
div {
background: red;
font-size: 2em;
}
`)
@template(...)
class MyComponent extends Component {
// ...
}
The @style
decorator accepts a CSSStylesheet
as a parameter.
The best way to create this stylesheet is using the css
template function.
In addition to setting individual CSS properties on an element's "style"
attribute, you can also use the custom UIX "stylesheet"
attribute to apply a stylesheet to the scope of the element.
// normal "style" attribute:
<div style="color: red">...</div>;
// "stylesheet" attribute:
<div stylesheet="./MyStyle.css">
<h1>Title</h1>
</div>;
/* applies to the outer div*/
:scope {
color: green
}
/* applies to all h1 elements contained in the div*/
h1 {
font-size: 2em;
}
This is the preferred method over placing styles in the entrypoint.css
or a custom theme stylesheet, because the styles are always scoped to the element in which they are needed and never leaked out to other elements in the DOM.
Element-scoped styles can also be used inside function components, which do not support external style sheets like class components.
Warning
This feature only works in browsers that support the experimental @scope
block.
The css
function creates a CSSStylesheet
from any valid CSS string (@import directives are not allowed). Additionally, it supports reactive properties:
const fontSize: Ref<string> = $('10px');
const stylesheet: CSSStylesheet = css `
h1.big {
font-size: ${fontSize};
color: ${it => it.myColor};
}
`;
fontSize.val = '20px';
In this example, the font-size
property is bound to a pointer, and the color is bound to a computed value, where it
references an element for which the selector is applied.
The UIX.Theme
namespace, is used to register and activate global themes. Themes can be defined as dark or light mode themes.
By default, UIX automatically decides which mode (dark or light) to use, depending on the preferred operating system mode.
The default themes provided by UIX are uix-light
and uix-dark
. More information on native themes can be found in the Predefined Themes section.
You can create and apply a custom theme by using the registerTheme
method of UIX.Theme
. This allows you to define and apply a personalized visual style for your application's frontend and backend:
registerTheme(theme: {
name: string,
mode?: 'light' | 'dark',
values: Record<string, string>,
stylesheets?: (string | URL)[],
onActivate?: () => void,
onDeactivate?: () => void
});
Here’s an example of how to register a light theme:
import { UIX } from "uix";
UIX.Theme.registerTheme({
// unique theme name
name: 'my-custom-light-theme',
// light or dark (can be undefined if the theme doesn't respect dark/light mode preferences)
mode: 'light',
// custom CSS variables (e.g. var(--border-color-1))
values: {
'text': '#eeffee',
'border-color-1': '#ffaa00'
},
// custom globally applied stylesheets
stylesheets: [
'https://example.com/style.css'
],
onActivate() {
// called when theme is activated
},
onDeactivate() {
// called when theme is deactivted
}
});
Note
Registering themes does not necessarily activate the theme. You can activate a theme using the useThemes
method.
Themes can be activated via the useThemes
method of UIX.Theme
.
The first available (registered) dark-mode theme from the list is used
as the new dark-mode theme, the first light-mode theme from the list is used as the new light-mode theme.
When useThemes
is called, all previously activated themes are removed.
import { UIX } from "uix";
// activate themes - the current theme is selected depending on the dark/light mode preference
UIX.Theme.useThemes('my-custom-dark-theme', 'uix-light-plain');
Note
Themes should always be activated in both frontend and backend. To avoid duplicate code, put the theme activation in a common module and import it from both the backend and the frontend. Make sure that custom themes are also registered in a common module.
UIX provides a set of predefined themes that can be used out of the box.
Per default, the UIX themes uix-light
and uix-dark
are activated.
These themes are designed with a clean, professional look that fits a wide variety of applications, making them an excellent starting point for most UI projects.
If you don't want any predefined styles, you can use the plain themes uix-light-plain
and uix-dark-plain
. They only define basic text and background colors for dark and light mode, everything else is up to you.
UIX also offers full support for Tailwind CSS, a popular utility-first CSS framework that allows developers to rapidly build modern UIs using predefined CSS classes.
To use TailwindCSS in your UIX application, import the theme and apply it on both the frontend and backend:
import { UIX } from "uix";
import { tailwindcss } from "uix/themes/tailwindcss.ts";
UIX.Theme.useTheme(tailwindcss);
import "common/theme.ts";
import "common/theme.ts";
This will activate the TailwindCSS
theme, enabling you to write JSX with Tailwind utility classes:
export default <div class="text-red-500">
Hello, UIX!
</div>;
More information can be found in the Tailwind CSS documentation.
Note
We recommend using live reloading (uix -l
) during development to update Tailwind CSS styles and automatically reload the pages when changes are made.
It is recommended to let UIX automatically switch between the dark and light theme, but you can override the current mode:
UIX.Theme.setMode('dark');
For some use cases, it may be useful to change content or styling depending on the current theme or mode.
The theme
and mode
properties of UIX.Theme
are bound to reactive pointers and can be used in combination with effect
and always
to react to changes:
effect(() => console.log(`Mode changed to ${UIX.Theme.mode}`));
<div>
{always(() =>
UIX.Theme.mode == 'dark' ?
'Dark mode' :
'Light mode'
)}
</div>
Alternatively, you can access the underlying pointers directly with UIX.Theme.$.theme
/ UIX.Theme.$.mode
.