Styles
The fcore/styles module bridges Factorioβs two-stage GUI architecture: registering 50+ high-performance prototype styles in the modβs prototype stage (data.ts) and applying type-safe reactive inline overrides in JSX components during runtime (control.ts).
π How It Works: Prototype vs. Runtime Styling
All built-in GUI styles (windows, slot buttons, tabbed panes, well sections, status indicators) are automatically registered into data.raw["gui-style"].default when fcore is included as a mod dependency.
flowchart LR
subgraph DataStage["1. Prototype Stage (fcore data.lua)"]
direction TB
ModDep["fcore Mod Dependency"] --> Prototypes["data.raw['gui-style']<br/>(Registers 50+ prototype styles:<br/>Slots, Buttons, Tabs, Frames)"]
end
subgraph RuntimeStage["2. Runtime Stage (control.ts)"]
direction TB
JSX["<SlotButton color='yellow'<br/>styles={{ width: 40 }} />"]
Prototypes -.->|"Base style: 'react_slot_button_yellow'"| Elem["LuaGuiElement"]
JSX -.->|"Inline overrides (width, padding)"| Elem
end
DataStage --> RuntimeStage
π¨ 1. Component Style Variants
Built-in UI components provide type-safe props mapping directly to pre-registered Factorio prototype styles:
import { createElement } from "fcore/react";import { Button, SlotButton, Indicator } from "fcore/react-components";
export function StyleDemo() { return ( <> {/* Button action styles */} <Button caption="Confirm" style="confirm_button" onClick={() => {}} /> <Button caption="Delete" style="red_button" onClick={() => {}} /> <Button caption="Back" style="back_button" onClick={() => {}} />
{/* Slot button color variants */} <SlotButton color="yellow" item="iron-plate" /> <SlotButton color="red" item="copper-ore" /> <SlotButton color="green" item="electronic-circuit" /> <SlotButton color="blue" item="transport-belt" />
{/* Status indicators */} <Indicator color="green" tooltip="System Online" /> <Indicator color="red" tooltip="Fault Detected" /> <Indicator color="yellow" tooltip="Awaiting Trains" /> </> );}Style Name Types
Each GUI element type provides a dedicated union type for all valid style names:
ButtonStylesβ Vanilla and reactive button styles (react_slot_button_*,confirm_button,red_button, etc.)FrameStylesβ Window frames, shallow boxes, and inner panels (inside_shallow_frame,dialog_frame, etc.)LabelStylesβ Typography styles (react_frame_title,caption_label,bold_label, etc.)ScrollPaneStylesβ Scroll areas (react_naked_scroll_pane,scroll_pane_in_shallow_frame, etc.)TableStylesβ Grid layouts (react_table_white_lines,slot_table, etc.)FlowStylesβ Flow containers (react_indicator_flow,react_titlebar_flow, etc.)DropdownStyles,CheckboxStyles,SliderStyles,ProgressbarStyles,TabStyles,TabbedPaneStyles,ImageStyles, etc.
The universal StyleFor<E> type maps any element tag E to its valid style names:
// Full autocomplete on known styles, while seamlessly accepting custom string names:export type StyleFor<E extends string = string> = E extends GuiElementType ? ElementStyleMap[E] | (string & {}) : string;β‘ 2. Type-Safe Inline Overrides (styles={{ ... }})
Every JSX element accepts a styles prop for customizing runtime dimensions, margins, paddings, and alignments. Property names and types are strictly validated at compile-time via StylesFor<E>:
import { createElement } from "fcore/react";import { VFlow, HFlow, Label, Input } from "fcore/react-components";
export function CustomLayout() { return ( <VFlow styles={{ width: 380, padding: 12, gap: 8, horizontal_align: "center", }} > <HFlow styles={{ vertical_align: "center", gap: 10 }}> <Label caption="Network ID:" styles={{ width: 100, font: "default-bold" }} /> <Input text="42" styles={{ width: 140 }} /> </HFlow> </VFlow> );}Supported Runtime Properties
fcore provides complete compile-time type safety for 100% of Factorio 2.0 LuaStyle properties, accurately inferred for each specific element:
- Dimensions:
width,height,minimal_width,maximal_width,minimal_height,maximal_height - Layout & Spacing:
padding,top_padding,bottom_padding,left_padding,right_padding,margin,gap - Alignment:
horizontal_align("left"|"center"|"right"),vertical_align("top"|"center"|"bottom") - Stretch & Squash:
horizontally_stretchable,vertically_stretchable,horizontally_squashable - Typography (Labels & Buttons):
font,font_color,single_line,rich_text_setting - Element-Specific:
horizontal_spacingon flows,cell_paddingon tables,selected_font_coloron buttons
π‘ 3. Automatic Override Preservation
In native Factorio C++, assigning elem.style = "new_style" immediately resets all custom dimensions (width, height, padding) back to the prototypeβs default values.
The fcore Reconciler handles this automatically: whenever a base style changes dynamically, it re-applies all active styles overrides, ensuring layouts never collapse or glitch.
π 4. Registering Custom Prototype Styles
If your mod creates new prototype styles in data.ts, use getDefaultStyles() to access the global style table and type-check with satisfies:
import type { ButtonStyleSpecification, FrameStyleSpecification } from "factorio:prototype";import { getDefaultStyles } from "fcore/styles";
const styles = getDefaultStyles();if (styles) { styles.my_custom_button = { type: "button_style", parent: "button", default_font_color: [1, 0.8, 0], height: 36, } satisfies ButtonStyleSpecification;
styles.my_panel_frame = { type: "frame_style", parent: "inside_shallow_frame", padding: 16, } satisfies FrameStyleSpecification;}Since StyleFor<E> uses the open union pattern (string & {}), your custom style names (style="my_custom_button") work immediately in JSX components without requiring any type declarations or module augmentations.