Style JUI components, controls, and fragments using localised CSS, CSS variables, and style packs. Use this skill when the user asks to: add or modify CSS for a component/control/fragment, create a custom style variant, theme a component, use CSS variables, or asks about styling patterns. Also trigger when the user mentions ILocalCSS, CssResource, localised CSS, style pack, Config.Style, CSS variables, or asks how to style or theme a JUI element.
73
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Style components, controls, and fragments using localised CSS with name obfuscation, CSS variables for theming, and style packs for variant support.
CssDeclaration (base interface)
└── IComponentCSS -- component(), disabled(), focus()
└── IControlCSS -- invalid(), read_only(), waiting()SimpleComponent, Component<Config>): ILocalCSS extends IComponentCSSControl<V, C>): ILocalCSS extends IControlCSSILocalCSS extends CssDeclaration (or IComponentCSS when stronger isolation is needed)The standard pattern for component styling. Styles are obfuscated at compile time to prevent name clashing.
public class MyComponent extends SimpleComponent {
@Override
protected INodeProvider buildNode(Element el) {
return Wrap.$(el).$(root -> {
root.style(styles().component());
Div.$(root).style(styles().header()).$(header -> {
H3.$(header).text("Title");
});
Div.$(root).style(styles().body());
}).build();
}
/************************************************************************
* CSS.
************************************************************************/
@Override
protected ILocalCSS styles() {
return LocalCSS.instance();
}
public static interface ILocalCSS extends IComponentCSS {
String header();
String body();
}
@CssResource(value = {
IComponentCSS.COMPONENT_CSS
}, stylesheet = """
.component {
display: flex;
flex-direction: column;
}
.component .header {
padding: 8px 12px;
font-weight: 600;
}
.component .body {
flex: 1;
padding: 12px;
}
""")
public static abstract class LocalCSS implements ILocalCSS {
private static LocalCSS STYLES;
public static ILocalCSS instance() {
if (STYLES == null) {
STYLES = (LocalCSS) GWT.create(LocalCSS.class);
STYLES.ensureInjected();
}
return STYLES;
}
}
}Key rules:
ILocalCSS extends IComponentCSS for components or IControlCSS for controls@CssResource must include IComponentCSS.COMPONENT_CSS (and IControlCSS.CONTROL_CSS for controls).component class is applied automatically by SimpleComponent to the root element.component (e.g. .component .header) for isolationmy_style() not my-style()styles().methodName() (names are obfuscated)Controls extend the CSS hierarchy with additional state classes.
public static interface ILocalCSS extends IControlCSS {
String inner();
String label();
}
@CssResource(value = {
IComponentCSS.COMPONENT_CSS,
IControlCSS.CONTROL_CSS
}, stylesheet = """
.component {
/* Control container */
}
.component .inner {
/* Input area */
}
""")
public static abstract class LocalCSS implements ILocalCSS {
private static LocalCSS STYLES;
public static ILocalCSS instance() {
if (STYLES == null) {
STYLES = (LocalCSS) GWT.create(LocalCSS.class);
STYLES.ensureInjected();
}
return STYLES;
}
}IControlCSS provides the following styles (managed automatically by the framework):
| Style | When applied |
|---|---|
component() | Always on the root element |
disabled() | When the control is disabled |
focus() | When the control has focus |
invalid() | When validation fails |
read_only() | When the control is read-only |
waiting() | When the control is in a loading state |
Fragments have two styling approaches.
public class MyFrag extends Fragment<MyFrag> {
static {
CSSInjector.injectFromModuleBase("MyFrag.css");
}
public MyFrag() {
super(parent -> {
Div.$(parent).style("fragMyFrag").$(inner -> {
Span.$(inner).style("title").text("Hello");
});
});
}
}Scope styles using a unique class name prefix (e.g. fragMyFrag):
.fragMyFrag {
display: flex;
gap: 8px;
}
.fragMyFrag > .title {
font-weight: 600;
}public class MyFrag extends Fragment<MyFrag> {
protected ILocalCSS styles() {
return LocalCSS.instance();
}
public interface ILocalCSS extends CssDeclaration {
String wrapper();
String title();
}
@CssResource(stylesheet = """
.wrapper {
display: flex;
gap: 8px;
}
.title {
font-weight: 600;
}
""")
public static abstract class LocalCSS implements ILocalCSS {
private static LocalCSS STYLES;
public static ILocalCSS instance() {
if (STYLES == null) {
STYLES = (LocalCSS) GWT.create(LocalCSS.class);
STYLES.ensureInjected();
}
return STYLES;
}
}
}CSS variables enable theming without replacing stylesheets. Declare component-specific variables on the .component class and reference them throughout.
@CssResource(value = {
IComponentCSS.COMPONENT_CSS
}, stylesheet = """
.component {
--jui-toolbar-bg: #fafafa;
--jui-toolbar-gap: 2px;
--jui-toolbar-btn-color: #444;
--jui-toolbar-btn-hover-bg: #e8e8e8;
--jui-toolbar-btn-active-bg: #dbeafe;
--jui-toolbar-btn-active-color: #1d4ed8;
}
.toolbar {
background: var(--jui-toolbar-bg);
gap: var(--jui-toolbar-gap);
}
.tbtn {
color: var(--jui-toolbar-btn-color);
}
.tbtn:hover {
background: var(--jui-toolbar-btn-hover-bg);
}
.tbtnActive {
background: var(--jui-toolbar-btn-active-bg);
color: var(--jui-toolbar-btn-active-color);
}
""")Users can override variables via an auxiliary CSS class (global or injected):
.my-custom-toolbar {
--jui-toolbar-bg: #1e293b;
--jui-toolbar-btn-color: #e2e8f0;
--jui-toolbar-btn-hover-bg: #334155;
}Applied via styles(...) configuration:
cfg.styles("my-custom-toolbar");Or inline via css(...):
cfg.css("--jui-toolbar-bg: #1e293b;");--jui-color-*, --jui-ctl-*, --jui-btn-*, --jui-state-*--jui-componentname-* (e.g. --jui-toolbar-bg).component {
--cpt-btn-bg: var(--jui-btn-bg);
--cpt-btn-text: var(--jui-btn-text);
--cpt-btn-disabled-bg: var(--jui-state-disabled-bg);
}Components, controls and fragments are generally configured through variants: a variant is a named, reusable bundle of configuration — a style, but also CSS variable overrides, structural options (icon, layout direction), padding, colour scheme, etc. — that can be applied to an artefact repeatably to give it a particular look or behaviour in a particular context. Rather than hand-setting half a dozen options at every call site, you name a variant once and reuse it.
Two concrete mechanisms implement this idea:
Fragments use IFragmentVariant<T> — a functional interface whose configure(fragment) applies
settings to the fragment. Apply with .variant(...). Variants are declared as constants on a
Variant (or similarly named) interface and compose: a higher-level variant can apply others.
public interface Variant extends IFragmentVariant<BtnFragment> {
Variant STANDARD = fragment -> { };
Variant ROUNDED = fragment -> fragment.css("--frag-btn-radius: 16px;");
Variant OUTLINED = fragment -> fragment.css("""
--frag-btn-text: var(--frag-btn-border);
--frag-btn-bg: var(--jui-color-aux-white);
""");
// Composition: a variant built from other variants.
Variant OUTLINED_ROUNDED = fragment -> fragment.variant(OUTLINED).variant(ROUNDED);
}Btn.$(parent, "Save").variant(Btn.Variant.OUTLINED_ROUNDED);A fragment may expose more than one variant axis (e.g. Btn separates visual Variant from colour
Nature — WARNING, DANGER, SUCCESS), each applied independently.
Components and controls use the style pack pattern below: a Style interface declared in
Config, with named Style constants chosen via cfg.style(...). A Style carries an ILocalCSS
and may carry further structural configuration (see Style with additional configuration).
Variants classVariants are a project-level concern as much as a framework one. A project typically collects its own
variants in a dedicated Variants class (e.g. …/ui/Variants.java) — a home for the named looks
and configurations the application reuses across screens, layered on top of (or composed from) the
framework's standard variants. Treat it like a small in-house design vocabulary:
public final class Variants {
// A project look for primary actions, reused everywhere.
public static final Btn.Variant PRIMARY_ACTION = fragment ->
fragment.variant(Btn.Variant.STANDARD_EXPANDED_ROUNDED).variant(Btn.Nature.SUCCESS);
// A custom style-pack variant for a standard/custom component (see "Creating Custom Styles").
public static final MyCard.Config.Style HEADLINE = MyCard.Config.Style.create(HeadlineCSS.instance());
}When working in a project, look for its Variants class first and reuse the variants defined
there for consistency, adding new ones to it rather than inlining one-off configuration at the call
site.
Style packs are the variant mechanism for components and controls: they allow a component to
support multiple visual variants (e.g. a button with normal, outlined, and link styles). Each variant
provides its own ILocalCSS implementation with different stylesheets.
public class MyComponent extends Component<MyComponent.Config> {
public static class Config extends Component.Config {
public interface Style {
public ILocalCSS styles();
public static Style create(ILocalCSS styles) {
return () -> styles;
}
public static final Style NORMAL = create(NormalCSS.instance());
public static final Style COMPACT = create(CompactCSS.instance());
}
private Style style = Style.NORMAL;
public Config style(Style style) {
if (style != null)
this.style = style;
return this;
}
@Override
@SuppressWarnings("unchecked")
public MyComponent build(LayoutData... data) {
return (MyComponent) super.build(new MyComponent(this), data);
}
}
public MyComponent(Config config) {
super(config);
}
@Override
protected ILocalCSS styles() {
return config().style.styles();
}
// Style interface shared by all variants.
public static interface ILocalCSS extends IComponentCSS {
String header();
String body();
}
// Variant 1: Normal.
@CssResource(value = {
IComponentCSS.COMPONENT_CSS
}, stylesheet = """
.component {
border: 1px solid #ddd;
border-radius: 6px;
}
.component .header {
padding: 12px 16px;
font-size: 1em;
}
.component .body {
padding: 16px;
}
""")
public static abstract class NormalCSS implements ILocalCSS {
private static NormalCSS STYLES;
public static ILocalCSS instance() {
if (STYLES == null) {
STYLES = (NormalCSS) GWT.create(NormalCSS.class);
STYLES.ensureInjected();
}
return STYLES;
}
}
// Variant 2: Compact.
@CssResource(value = {
IComponentCSS.COMPONENT_CSS
}, stylesheet = """
.component {
border: 1px solid #eee;
border-radius: 4px;
}
.component .header {
padding: 4px 8px;
font-size: 0.85em;
}
.component .body {
padding: 8px;
}
""")
public static abstract class CompactCSS implements ILocalCSS {
private static CompactCSS STYLES;
public static ILocalCSS instance() {
if (STYLES == null) {
STYLES = (CompactCSS) GWT.create(CompactCSS.class);
STYLES.ensureInjected();
}
return STYLES;
}
}
}Usage:
new MyComponent.Config()
.style(MyComponent.Config.Style.COMPACT)
.build();The Style interface can carry more than just CSS. This is useful when variants differ in structure (icons, layout direction, etc.):
public interface Style {
public ILocalCSS styles();
public boolean vertical();
public String icon();
public static Style create(ILocalCSS styles, boolean vertical, String icon) {
return new Style() {
@Override
public ILocalCSS styles() { return styles; }
@Override
public boolean vertical() { return vertical; }
@Override
public String icon() { return icon; }
};
}
public static final Style HORIZONTAL = create(HorizontalCSS.instance(), false, FontAwesome.minus());
public static final Style VERTICAL = create(VerticalCSS.instance(), true, FontAwesome.plus());
}Components can expose a static DEFAULT_STYLE field to allow application-wide defaults:
public static Config.Style DEFAULT_STYLE = Config.Style.NORMAL;
public static class Config extends Component.Config {
private Style style = (DEFAULT_STYLE != null) ? DEFAULT_STYLE : Style.NORMAL;
// ...
}Applications override the default at startup:
MyComponent.DEFAULT_STYLE = MyComponent.Config.Style.COMPACT;Custom styles can be created outside a component's class. This is the primary mechanism for restyling library components.
@CssResource(value = {
IComponentCSS.COMPONENT_CSS
}, stylesheet = """
.component {
border: 2px solid #4f46e5;
border-radius: 12px;
background: #eef2ff;
}
.component .header {
padding: 16px 20px;
color: #4338ca;
font-weight: 700;
}
.component .body {
padding: 20px;
}
""")
public abstract class CustomMyComponentCSS implements MyComponent.ILocalCSS {
public static final MyComponent.Config.Style CUSTOM = MyComponent.Config.Style.create(instance());
private static MyComponent.ILocalCSS STYLES;
public static MyComponent.ILocalCSS instance() {
if (STYLES == null) {
STYLES = (CustomMyComponentCSS) GWT.create(CustomMyComponentCSS.class);
STYLES.ensureInjected();
}
return STYLES;
}
}Usage:
new MyComponent.Config()
.style(CustomMyComponentCSS.CUSTOM)
.build();The custom class implements MyComponent.ILocalCSS and provides its own stylesheet. The Style.create() factory wraps it into a Style instance that can be passed to the component's config.
For larger stylesheets, reference external CSS files instead of inlining. Files are resolved relative to the classpath.
@CssResource({
IComponentCSS.COMPONENT_CSS,
"com/myapp/ui/MyComponent.css",
"com/myapp/ui/MyComponent_Override.css"
})
public static abstract class LocalCSS implements ILocalCSS {
// ...
}The override pattern (_Override.css) is used by library components: the main stylesheet contains the defaults and the override file is initially empty. Projects replace the override file using super-source to customise without modifying the original.
Styles declared in ILocalCSS are obfuscated and must be referenced via styles().methodName(). Styles that exist in the stylesheet but are not declared in ILocalCSS retain their original names and can be referenced as plain strings:
// Obfuscated (declared in ILocalCSS)
root.style(styles().header());
// Plain (exists in CSS but not in ILocalCSS)
root.style("my_plain_style");Styles inherited from IComponentCSS (such as component, disabled, focus) are always obfuscated and must be accessed via the interface methods.
When styling a JUI element:
IComponentCSS for components, IControlCSS for controls, CssDeclaration for fragmentsILocalCSS -- add methods for each custom style classstylesheet = """...""" or reference external filesIComponentCSS.COMPONENT_CSS (and IControlCSS.CONTROL_CSS for controls) in the @CssResource annotation.component (e.g. .component .header)IFragmentVariant<T> constants; for components/controls add a style pack (Style interface in Config with create() factory and variant constants). Reuse the project's Variants class where one exists, and add new shared variants thereILocalCSS in an external class with its own @CssResource annotation and stylesheet3639345
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.