This guide is the technical reference for engineers, architects, and maintainers who integrate, build, customize, secure, or contribute to Semantic UI. Where the User Guide covers how to use the framework, this guide covers how it is built — the LESS theming pipeline, the JavaScript module architecture, the Gulp build system, the configuration surface, security considerations, and the contribution workflow. It is written against Semantic UI 2.5.0 (source commit 597843a).
Table of Contents
- Executive Summary
- Architecture
- Requirements
- The Build System
- Configuration Reference
- Customization Deep Dive (Theming)
- The JavaScript Module Architecture
- Security
- Testing Strategy
- Operations & Performance
- Component Internals Reference
- Troubleshooting & Known Issues
- Improvements & Technical Debt
- Contributing
- Quick Reference
1. Executive Summary
Semantic UI is a CSS-first front-end framework whose value proposition is theming. It is built around three architectural pillars:
- A LESS source tree organized by a five-category component taxonomy (Globals, Elements, Collections, Views, Modules). Roughly 50+ components are authored as LESS, exposing ~3000 CSS variables for customization.
- A three-level theme-inheritance model (default theme → packaged theme → site theme) wired together with LESS
@import (optional)directives, selected per-component via atheme.configfile. This is the framework's distinguishing design and the reason its README calls it "a UI framework designed for theming." - A jQuery-based JavaScript layer of 16 interactive Modules and 3 Behaviors, all following a uniform plugin pattern (initialize → invoke-behavior-by-string → settings object with callbacks and debug instrumentation).
The repository ships precompiled output in dist/ (combined and per-component CSS/JS) plus a Gulp 4 build system that compiles a developer's themed LESS into a customized bundle. An interactive installer scaffolds project configuration on first npm install.
| Attribute | Value |
|---|---|
| Version | 2.5.0 (released Oct 6, 2022) |
| License | MIT |
| Source language | LESS (styles) + ES5 JavaScript / jQuery (modules) |
| Runtime dependency | jQuery ^3.5.1 (for Modules/Behaviors only) |
| Build system | Gulp 4 + LESS + autoprefixer + clean-css + uglify |
| Component count | 16 Elements + 6 Collections + 6 Views + 16 Modules + 3 Behaviors + 2 Globals |
| Packaged themes | 23 |
| Total source | ~526 files, ~320K source chars |
Note
Semantic UI is the upstream "vanilla" framework. Several official sibling distributions are maintained as separate repositories:
semantic-ui-css(precompiled),semantic-ui-less(LESS only), and framework integrations for React, Angular, Ember, and Meteor. Architectural decisions here (notably the jQuery dependency) explain why those wrappers exist.
2. Architecture
2.1 High-level structure
┌──────────────────────────────────────┐
│ src/ (authored source) │
├──────────────────────────────────────┤
theme.config ───────► │ definitions/ LESS + JS per │
(per-component theme │ ├── globals/ component │
selection) │ ├── elements/ │
│ ├── collections/ │
site/ ──────────────► │ ├── views/ │
(your overrides) │ ├── modules/ (LESS + .js) │
│ └── behaviors/ (.js only) │
themes/ ────────────► │ themes/ 23 packaged themes │
(default + packaged) │ └── <theme>/<type>s/<comp>.variables
│ + .overrides │
└───────────────┬──────────────────────┘
│ gulp build
┌──────────────────▼───────────────────┐
│ LESS compile → autoprefix → │
│ concat → clean-css → uglify │
└──────────────────┬───────────────────┘
▼
┌──────────────────────────────────────┐
│ dist/ │
│ semantic.css / .min.css │
│ semantic.js / .min.js │
│ components/<comp>.css|js (+min) │
│ themes/ (fonts + image assets) │
└──────────────────────────────────────┘
2.2 The component taxonomy
The five categories are not cosmetic — they determine whether a component has JavaScript and where its files live.
| Category | Has LESS | Has JS | Semantics |
|---|---|---|---|
Globals (reset, site) |
Yes | site only |
Page-wide reset + global site variables |
| Elements (16) | Yes | No | Atomic building blocks (button, icon, input…) |
| Collections (6) | Yes | No | Groups of elements (form, grid, menu, table…) |
| Views (6) | Yes | No | Content presentations (card, feed, comment…) |
| Modules (16) | Yes | Yes | Interactive widgets (dropdown, modal, popup…) |
| Behaviors (3) | No | Yes | JS-only helpers (api, form, visibility) |
This split is load-bearing for the build: CSS-only categories compile to stylesheet output only, while Modules emit both a .css and a .js in dist/components/, and Behaviors emit .js only.
2.3 The LESS import cascade
The heart of the theming architecture is src/theme.less, which every component imports. For a given component it resolves variables and overrides by importing up to four layers in priority order:
/* Site (global) variables — default → packaged → component-theme → site */
@import "@{themesFolder}/default/globals/site.variables";
@import (optional) "@{themesFolder}/@{site}/globals/site.variables";
@import (optional) "@{themesFolder}/@{theme}/globals/site.variables";
@import (optional) "@{siteFolder}/globals/site.variables";
/* Component variables — default → packaged theme → site theme */
@import "@{themesFolder}/default/@{type}s/@{element}.variables";
@import (optional) "@{themesFolder}/@{theme}/@{type}s/@{element}.variables";
@import (optional) "@{siteFolder}/@{type}s/@{element}.variables";
/* Component overrides (custom rules) — packaged theme → site theme */
.loadUIOverrides() {
@import (optional) "@{themesFolder}/@{theme}/@{type}s/@{element}.overrides";
@import (optional) "@{siteFolder}/@{type}s/@{element}.overrides";
}
The @theme variable is resolved dynamically per component: @theme: @@element; reads the value of the per-component theme variable defined in theme.config (e.g. @button: 'github' makes @theme equal 'github' while compiling the button). @import (optional) means a layer is silently skipped if that theme doesn't define the file — which is why a packaged theme only needs to ship the components it actually restyles.
Important
This cascade is the single most important architectural fact in the codebase. Variables flow
default → packaged → sitewith later winning;.overridesfiles add raw CSS rules with access to all resolved variables. A maintainer reading or extending the theme system must understandtheme.lessbefore anything else.
2.4 The JavaScript module pattern
Every Module and Behavior is an IIFE that registers a jQuery plugin and follows an identical skeleton (illustrated with dropdown):
(function ($, window, document) {
$.fn.dropdown = function (parameters) {
// for each matched element:
// - read merged settings (defaults ← $.fn.dropdown.settings ← call args ← data-* attrs)
// - build a `module` object with all methods
// - module.initialize() binds events, caches DOM
// - module.invoke(query) dispatches string method calls
// - instance stored via $.data(element, moduleNamespace)
};
$.fn.dropdown.settings = { /* defaults, callbacks, selectors, className, error, metadata */ };
})(jQuery, window, document);
Key shared sub-objects inside every settings:
| Sub-object | Role |
|---|---|
| (top-level keys) | Behavioral defaults (on, transition, duration, …) |
on* callbacks |
Lifecycle hooks the integrator overrides |
selector |
CSS selectors the module uses to find sub-parts |
className |
State class names the module toggles (active, visible, …) |
metadata |
data-* attribute names the module reads/writes |
error |
Human-readable error strings (logged on misuse) |
regExp / text / message |
Module-specific lookups and user-facing strings |
The invoke dispatcher is what makes $('.ui.modal').modal('show') work: the string 'show' is resolved against the module object's methods. This pattern is uniform across all 19 JS files, so understanding one module's structure transfers to all of them.
3. Requirements
| Concern | Requirement | Notes |
|---|---|---|
| Runtime (browser) | jQuery 3.x (^3.5.1) |
Required only for Modules + Behaviors. CSS components need nothing. |
| Build (Node) | Node.js 18+ | 2.5.0 updated scripts to build under Node 18. |
| Build (Gulp) | Gulp 4 | All tasks rewritten for Gulp 4 in 2.5.0 (was Gulp 3). |
| Build (LESS) | bundled via gulp-less |
Source contains no vendor prefixes; autoprefixer runs in the build. |
| Browser targets | Last 2 FF/Chrome/Safari(Mac), IE 11+, Edge 12+, Android 4.4+, iOS Safari 7+ | Flexbox components (grid) unsupported on IE9. |
Build-tool dependencies
The package.json declares a Gulp-centric toolchain (also mirrored in peerDependencies):
| Dependency | Role |
|---|---|
gulp, gulp-less |
Task runner + LESS compilation |
gulp-autoprefixer |
Adds vendor prefixes (source has none) |
gulp-clean-css |
CSS minification |
gulp-uglify |
JS minification |
gulp-concat, gulp-concat-css, gulp-rename, gulp-flatten, gulp-copy |
File assembly |
gulp-rtlcss |
RTL stylesheet generation |
gulp-header |
License banner injection |
yamljs |
Reads YAML build config |
jquery ^3.5.1 |
Runtime dependency vendored for tests/dist |
Note
Skipping a dependency-documentation lookup for these is intentional: they are well-known build tools, and the framework's own source is the authoritative description of how it uses them. The interesting integration is the
theme.lesscascade and the Gulp task graph, not the individual plugins' APIs.
4. The Build System
4.1 Gulp task graph
gulpfile.js wires the tasks defined under tasks/:
| Task | Source | Purpose |
|---|---|---|
build |
tasks/build.js |
Full build: CSS + JS + assets |
build-css |
tasks/build/css.js |
LESS → autoprefix → concat → minify → dist/ |
build-javascript |
tasks/build/javascript.js |
Concatenate + uglify module JS → dist/ |
build-assets |
tasks/build/assets.js |
Copy fonts + images to dist/themes/ |
watch |
tasks/watch.js |
Incremental rebuild on file change |
clean |
tasks/clean.js |
Remove dist/ |
version |
tasks/version.js |
Print/stamp version |
install |
tasks/install.js |
Interactive installer (see §4.3) |
check-install |
tasks/check-install.js |
Default task — verifies setup, runs installer if unconfigured |
build-rtl / watch-rtl |
tasks/rtl/ |
RTL builds (enabled when semantic.json.rtl is true) |
serve-docs / build-docs |
tasks/docs/ |
Documentation site integration |
The default Gulp task is check-install, so a bare gulp on an unconfigured project triggers the installer rather than failing.
4.2 Build output
A full build produces, in dist/:
semantic.css/semantic.min.css— every component, combinedsemantic.js/semantic.min.js— every module, combinedcomponents/<name>.css|js(+.min) — per-component files for selective inclusionthemes/— icon fonts and image assets referenced by the CSS
Tip
The per-component output in
dist/components/is the supported mechanism for shrinking payload: an integrator includes only the components their app uses instead of the full bundle. This is the framework's answer to tree-shaking, which LESS cannot do automatically.
4.3 The interactive installer
tasks/install.js runs a prompt-driven wizard (via the prompt-sui library). It:
- Detects an existing
semantic.jsonand offers to extend or skip. - Confirms the project root (or accepts a custom absolute path).
- Asks where to place Semantic UI inside the project.
- Offers three setup modes:
- Automatic — default locations, all components.
- Express — choose components + output folder.
- Custom — customize all
src/distpaths.
- Presents a component checkbox list for selective installs.
- Writes
semantic.json,theme.config, and thesite/folder from their.example/_sitetemplates.
Note
The installer is what renames
theme.config.example → theme.configand_site/ → site/. For manual installs (no installer), these renames must be done by hand, as documented insrc/README.md.
5. Configuration Reference
There are three configuration artifacts. They control what theme each component uses, where build files live, and the values inside each theme.
5.1 theme.config — per-component theme selection
A LESS file (from theme.config.example) assigning a theme name to every component, grouped by category, plus folder paths:
/* Global */ @site: 'default'; @reset: 'default';
/* Elements */ @button: 'default'; @input: 'default'; …
/* Modules */ @dropdown: 'default'; @modal: 'default'; …
/* Folders */
@themesFolder : 'themes'; /* path to packaged themes */
@siteFolder : 'site'; /* path to YOUR overrides */
@import (multiple) "theme.less";
To restyle a component, set its variable to any theme name present in src/themes/ (e.g. @button: 'material';). All 50+ component variables plus @themesFolder and @siteFolder are configurable here.
5.2 semantic.json — build paths and flags
A JSON file (from semantic.json.example) read by the build tools:
| Key | Default | Purpose |
|---|---|---|
base |
"" |
Base path prepended to all paths |
paths.source.config |
src/theme.config |
Where the theme config lives |
paths.source.definitions |
src/definitions/ |
Component LESS+JS |
paths.source.site |
src/site/ |
Site overrides |
paths.source.themes |
src/themes/ |
Packaged themes |
paths.output.packaged |
dist/ |
Combined bundle output |
paths.output.uncompressed |
dist/components/ |
Per-component, unminified |
paths.output.compressed |
dist/components/ |
Per-component, minified |
paths.output.themes |
dist/themes/ |
Asset output |
paths.clean |
dist/ |
Directory cleaned by gulp clean |
permission |
false |
File permission (chmod) to apply to output |
autoInstall |
false |
Re-run install automatically |
rtl |
false |
Enable RTL build tasks (true, false, or 'both') |
5.3 Global LESS variables (site.variables)
The most-changed global variables live in themes/default/globals/site.variables. Override them in site/globals/site.variables:
| Variable | Default | Controls |
|---|---|---|
@emSize |
14px |
The base size; everything scales from it |
@fontSize |
14px |
Body text size |
@fontName |
'Lato' |
Primary font family |
@headerFont / @pageFont |
Lato stack | Header / body font stacks |
@importGoogleFonts |
true |
Whether to fetch the font from Google Fonts at runtime |
@googleFontRequest |
derived | The exact Google Fonts URL query |
@primaryColor |
@blue |
Primary brand color |
@secondaryColor |
@black |
Secondary brand color |
@bold / @normal |
bold / normal |
Font weights |
@defaultBorderRadius |
@absoluteBorderRadius (4px) |
Corner rounding baseline |
@h1–@h5 |
rem ratios | Heading sizes |
Each component additionally has its own <component>.variables file (e.g. elements/button.variables exposes @backgroundColor, @verticalPadding, @horizontalPadding, @borderRadius, shadow variables, and more). With ~3000 variables across the framework, the per-component variable file is that component's configuration reference — inspect themes/default/<type>s/<component>.variables to see every knob.
5.4 JavaScript module settings
Each Module/Behavior exposes $.fn.<module>.settings. All share a common instrumentation core:
| Setting | Default | Purpose |
|---|---|---|
silent |
false |
Suppress all console output |
debug |
false |
Log internal events |
verbose |
false |
Verbose internal logging |
performance |
true |
Emit a performance trace |
name |
(module) | Name shown in logs |
namespace |
(module) | Event/data namespace |
Module-specific keys, callbacks, selectors, className maps, metadata maps, and error strings are defined alongside these. The complete callback inventory per module is in §11.
6. Customization Deep Dive (Theming)
There are three layers of customization, in increasing specificity. A maintainer should steer integrators toward the highest-numbered layer that solves their problem.
Layer 1 — Pick a packaged theme (theme.config)
Cheapest customization: set a component to one of the 23 shipped themes.
@button : 'github';
@menu : 'material';
Layer 2 — Override variables (site/**/<component>.variables)
Change values without writing CSS. The site theme is always the last @import in the cascade, so it wins.
/* site/globals/site.variables */
@primaryColor : @teal;
@fontName : 'Inter';
@emSize : 16px;
/* site/elements/button.variables */
@borderRadius : 0;
Layer 3 — Custom CSS (site/**/<component>.overrides)
For rules no variable exposes. .overrides files are imported after variables and have access to all of them.
/* site/elements/button.overrides */
.ui.button.brand {
background: linear-gradient(@primaryColor, darken(@primaryColor, 10%));
}
Caution
Do not customize by writing
!importantoverrides against compiledsemantic.css. That fights the cascade, breaks on upgrade, and discards the entire theming system. The supported path is variables → overrides → rebuild.
Color system
Named colors (@blue, @red, @green, @teal, …) and @primaryColor/@secondaryColor are defined once and consumed everywhere. Overriding @primaryColor re-skins primary buttons, active menu items, focused inputs, progress bars, and more in one change — the framework's "shared vocabulary" applied to color.
7. The JavaScript Module Architecture
7.1 Settings resolution order
When $('.ui.x').x(opts) runs, settings are merged from (lowest to highest priority):
$.fn.x.settings(framework defaults)- A global override of
$.fn.x.settings(set once at app start) - The
optsobject passed at the call site data-*attributes on the element (per the module'smetadata/attribute parsing)
7.2 Instance lifecycle
- initialize — caches DOM (
module.refresh), binds namespaced events, optionally fires init callbacks (fireOnInit). - invoke — the string-dispatch entry point;
x('method', args)resolvesmethodagainst the instance. - setting — read/write any setting at runtime (
x('setting', 'debug', true)). - destroy — unbinds all namespaced events and clears
$.data, leaving the DOM intact.
Because events are bound under a per-instance namespace, multiple instances and clean teardown are race-free — destroy removes exactly that instance's handlers.
7.3 Inter-module dependencies
| Module | Depends on |
|---|---|
dropdown, modal, dimmer, popup, sidebar, etc. |
transition (for show/hide animations) — emits the noTransition error if absent |
modal |
dimmer (creates the backdrop) |
dropdown (remote), search, tab (remote) |
api behavior (AJAX) |
Important
When building a custom per-component JS bundle, you must include the transitive dependencies. A
dropdown.jswithouttransition.jsthrowsThis module requires ui transitionsat runtime. The safest minimal set for any animated module is{ component, transition }, plus{ dimmer }for modal and{ api }for remote data.
8. Security
Semantic UI is primarily CSS, but its JavaScript layer renders HTML and makes network requests, which creates a real (if narrow) security surface. Treat the items below as a checklist for any app embedding user-generated content.
8.1 HTML rendering / XSS
Several modules render content that can be HTML:
- Dropdown has
preserveHTML: trueby default — selected values, labels, and menu text are inserted as HTML, not escaped. - Popup content (
data-content/content/html) is rendered into the popup. - Search renders result templates.
Caution
If any of these render user-supplied or server-reflected strings, set
preserveHTML: false(dropdown, popup, search) so values are escaped, or sanitize the input server-side before it reaches the DOM. The framework does not ship an HTML sanitizer of its own; escaping is the integrator's responsibility. This is the most important security control for Semantic UI apps.
8.2 The api behavior
The api behavior builds request URLs from templates with {name} placeholders filled from urlData and element data-* attributes. Risks and mitigations:
- URL/template injection — never place untrusted values into
urltemplates without encoding; prefer server-side allowlists of endpoints (theapimap) over client-built URLs. - CSRF —
apidoes not add CSRF tokens automatically; configurebeforeXHR/headers to attach them. - Response handling —
onSuccessreceives the parsed response; do not.html()it unescaped.
8.3 Network/privacy: Google Fonts
By default (@importGoogleFonts: true), compiled CSS contains @import url(https://fonts.googleapis.com/...). This causes every visitor's browser to contact Google. For privacy regimes (GDPR), strict CSP, or offline deployments:
- Set
@importGoogleFonts: falseand self-host the font. - Or pin a CSP
font-src/style-srcthat permits the Google domains intentionally.
(See also GitHub #7146, where the Google requests surfaced as runtime errors.)
8.4 Dependency posture
- The runtime dependency is jQuery
^3.5.1. Track jQuery security advisories and pin a patched 3.x in your own app; the framework's floor is 3.5.1. - An open security report exists upstream (GitHub #7154, "Open vulnerability flagged by security team"). Maintainers and adopters should monitor it. Consistent with responsible disclosure, specifics are not reproduced here; review the upstream issue and apply any published guidance.
Warning
Because development cadence has slowed (see §13), do not assume timely upstream security patches. For long-lived deployments, budget for self-maintaining the dependency tree or evaluate an actively maintained community fork.
9. Testing Strategy
9.1 Framework
Tests run under Karma + Jasmine (karma.conf.js). The harness loads jQuery, the compiled CSS (from docs/build), all module source from src/definitions/**/*.js, shared helpers from test/helpers/, HTML fixtures from test/fixtures/, and the specs.
9.2 Coverage
Specs exist for the interactive modules where behavior is most testable:
test/modules/
accordion.spec.js checkbox.spec.js dropdown.spec.js
modal.spec.js popup.spec.js search.spec.js
shape.spec.js sidebar.spec.js tab.spec.js
module.spec.js (shared module-contract tests)
Note
Coverage is concentrated on Modules (the JS surface). Pure-CSS Elements/Collections/Views are validated visually via the
examples/HTML pages rather than by unit tests — a reasonable strategy for a CSS framework, but it means stylesheet regressions are caught by eye, not by CI assertion. There is atest/meteor/suite for the Meteor integration and atest/coverage/output directory.
9.3 Visual/manual testing
The examples/ directory (grid.html, responsive.html, sticky.html, theming.html, login.html, etc.) doubles as a manual test surface. The src/README.md recommends running gulp watch, editing theme files, and refreshing an example page to inspect theme changes.
10. Operations & Performance
10.1 Payload management
| Lever | Effect |
|---|---|
Use dist/components/* selectively |
Ship only components in use — the primary size lever |
Minified bundles (*.min.css/js) |
Production default |
| Drop unused themes | Don't ship dist/themes/<unused> assets |
| Self-host / subset the icon font | The icon font is a notable fixed cost |
| Disable Google Fonts import | Removes a runtime network round-trip |
Tip
The full
semantic.min.csscontains all ~50 components plus the icon font. Most applications use a fraction; the per-component build is how you avoid shipping the rest. There is no automatic dead-CSS elimination in the LESS pipeline.
10.2 Build performance
gulp watchdoes incremental compilation — only the touched component and its dependents rebuild.- A full
gulp buildrecompiles every component's four-layer LESS cascade; on large custom theme sets this is the slow path. Run it for releases, not on every edit.
10.3 Caching & CDN
dist/ output is fully static. Serve with long-lived cache headers and fingerprinted filenames. The CDN distributions (cdnjs / jsDelivr) are appropriate for the default theme.
11. Component Internals Reference
11.1 Module callback inventory
| Module | Callbacks |
|---|---|
accordion |
onOpen, onOpening, onClose, onClosing, onChange, onChanging |
checkbox |
onChange, onChecked, onUnchecked, onIndeterminate, onDeterminate, onEnable, onEnabled, onDisable, onDisabled |
dimmer |
onShow, onHide, onChange, onStart, onComplete |
dropdown |
onChange, onAdd, onRemove, onLabelSelect, onLabelCreate, onLabelRemove, onNoResults, onShow, onHide |
embed |
onCreate, onDisplay, onPlaceholderDisplay, onEmbed, onPlay, onPause, onStop, onReset |
modal |
onShow, onVisible, onHide, onHidden, onApprove, onDeny, onStart, onComplete |
nag |
(none — persistence via cookie/localStorage) |
popup |
onCreate, onShow, onVisible, onHide, onHidden, onRemove, onUnplaceable |
progress |
onChange, onSuccess, onWarning, onError, onActive, onNumeric, onLabelUpdate |
rating |
onRate |
search |
onSelect, onResults, onResultsAdd, onSearchQuery, onResultsOpen, onResultsClose, onSuccess, onError, onFailure, onAbort, onComplete, onText, onURL |
shape |
onChange |
sidebar |
onShow, onVisible, onHide, onHidden, onChange |
sticky |
onStick, onUnstick, onTop, onBottom, onScroll, onReposition |
tab |
onLoad, onFirstLoad, onRequest, onSuccess, onVisible |
transition |
onStart, onShow, onHide, onComplete |
11.2 Behavior callback inventory
| Behavior | Callbacks |
|---|---|
api |
onRequest, onResponse, onSuccess, onComplete, onFailure, onError, onAbort |
form |
onValid, onInvalid, onSuccess, onFailure |
visibility |
onOnScreen, onOffScreen, onTopVisible/Reverse, onBottomVisible/Reverse, onPassing/Reverse, onPassed, onTopPassed/Reverse, onBottomPassed/Reverse, onFixed, onUnfixed, onLoad, onAllLoaded, onRefresh, onUpdate |
11.3 Source layout
src/
semantic.less # imports every component (build-tool-free path)
theme.less # the import cascade (default→packaged→site)
theme.config(.example) # per-component theme selection
definitions/
globals/{reset,site}.{less,js}
elements/<16>.less
collections/<6>.less
views/<6>.less
modules/<16>.{less,js}
behaviors/{api,form,visibility}.js
themes/<23 themes>/<type>s/<component>.{variables,overrides}
_site/ # template for the site theme (rename to site/)
tasks/ # Gulp build, install, rtl, docs, admin
dist/ # precompiled output (committed)
examples/ # manual/visual test pages
test/ # Karma+Jasmine specs, fixtures, helpers
12. Troubleshooting & Known Issues
Operational issues
| Symptom | Cause | Resolution |
|---|---|---|
$(...).modal is not a function |
jQuery missing or loaded after Semantic | Load jQuery first; include the module's JS |
| Icons render as boxes | Icon font not served at expected path | Ship dist/themes/ assets; configure font loader/@fontPath |
Module parse failed: Unexpected character '@' (#6771) |
Bundler importing CSS with no CSS loader | Add css-loader/style-loader |
This module requires ui transitions |
Animated module without transition |
Include transition.js |
googleProtocol/googleFonts errors (#7146) |
Google Fonts import failing/blocked | @importGoogleFonts: false + self-host |
semantic-ui-css fails in CRA (#7073) |
Missing CSS/font loaders | Use Semantic UI React, or configure loaders |
| Install fails (#7131, #7115) | Old Node/Gulp 3 | Node 18 + Gulp 4, or use semantic-ui-css |
Confirmed upstream bugs (from the issue tracker)
| Issue | Component | Summary |
|---|---|---|
| #5341 | Modal | Not working in some mobile browsers |
| #7153 | Modal | Page won't scroll after closing modal |
| #3236 | Sidebar | Doesn't toggle correctly in RTL build |
| #5670 | Input | Missing right border with action + error/focus |
| #7128 | Segment | Rendering bug |
| #5758 | Dropdown | Items not clickable on some iPhones |
| #7125 | Dropdown | Screen-reader (NVDA/JAWS) gaps in multiple-search-selection |
| #7154 | Security | Open vulnerability flagged (see §8.4) |
Note
The framework's bug board uses a
[Component]title convention and aConfirmed Buglabel. Browsing theConfirmed Bugtag is the maintainers' recommended way to track known issues — useful when triaging whether a report is new.
13. Improvements & Technical Debt
These are observations from the source and issue tracker, framed as the maintenance backlog an adopter should weigh.
- Maintenance cadence. The last release (2.5.0) is from October 2022 and primarily modernized the build for Node 18 / Gulp 4. The project's future has been discussed openly (issue #7108). Adopters of a new long-lived project should evaluate activity and actively maintained community forks before committing.
- jQuery dependency. The interactive layer is tied to jQuery, which is increasingly out of step with modern component frameworks. This is the structural reason the official React/Angular/Vue ecosystems use separate wrapper repos. A web-components or framework-agnostic rewrite would be a major architectural shift.
- ES5 JavaScript. Modules are pre-ES6 (
var, function expressions, IIFE). Modernizing to ES modules would enable real tree-shaking, which the LESS-only build cannot provide today. - No automatic CSS dead-code elimination. Payload control is manual (per-component imports). A PurgeCSS-style step is left to integrators.
- HTML escaping defaults.
preserveHTML: trueon dropdown is a foot-gun for user-content apps; a safer default (or a built-in sanitizer) would reduce XSS risk (§8.1). - Google Fonts on by default. The runtime Google dependency is a privacy/CSP liability that many teams must remember to disable (§8.3).
- Test coverage is module-only. CSS components rely on visual inspection; there are no stylesheet regression assertions in CI.
- RTL edge cases. Some components (e.g. sidebar, #3236) have known RTL defects; the RTL build is a generated transform, not hand-verified per component.
14. Contributing
The contribution workflow is defined in CONTRIBUTING.md:
- Usage questions go to Gitter / forums / StackOverflow — not GitHub Issues.
- Bug reports require a reproducible test case, ideally forked from the project's JSFiddle boilerplate. Bugs confirmed by a maintainer receive the
Confirmed Buglabel. - Issue titles follow the
[Component] Sub-type Should Do Correct Behaviorconvention in title case; enhancements use[Component] Add new feature. - Pull requests target the
nextbranch (notmaster/main). - Framework-integration bugs (Ember/Meteor/Angular/React) should be filed against those projects' boards, not the core repo.
Build/dev loop for contributors
git clone https://github.com/Semantic-Org/Semantic-UI.git
cd Semantic-UI
npm install # runs the installer; choose Automatic
gulp watch # rebuild on change
# edit src/definitions/** or src/themes/**, refresh examples/*.html
Admin/release tasks live under tasks/admin/ and tasks/collections/admin.js and are enabled only when config.admin is set — these handle distribution repos (the semantic-ui-css, -less, component repos) and are not needed for normal contributions.
15. Quick Reference
Gulp commands
| Command | Purpose |
|---|---|
gulp install |
Interactive setup wizard |
gulp build |
Full CSS + JS + assets build |
gulp build-css / build-javascript / build-assets |
Partial builds |
gulp watch |
Rebuild on change |
gulp clean |
Delete dist/ |
gulp build-rtl / watch-rtl |
RTL builds (needs rtl: true) |
gulp version |
Version info |
Configuration files
| File | From template | Purpose |
|---|---|---|
theme.config |
theme.config.example |
Per-component theme selection |
semantic.json |
semantic.json.example |
Build paths + rtl/autoInstall/permission |
site/ |
_site/ |
Your variable + override files |
Customization layers (least → most specific)
theme.config— pick a packaged theme per componentsite/**/*.variables— override variable valuessite/**/*.overrides— add custom CSS rules
JS API cheat sheet
$('.ui.x').x(); // initialize
$('.ui.x').x({ setting: value }); // initialize with settings
$('.ui.x').x('behavior', arg); // invoke a behavior
$('.ui.x').x('setting', 'k', v); // set a setting at runtime
$('.ui.x').x('destroy'); // teardown
Component categories
| Category | Count | JS? |
|---|---|---|
| Globals | 2 | site only |
| Elements | 16 | No |
| Collections | 6 | No |
| Views | 6 | No |
| Modules | 16 | Yes |
| Behaviors | 3 | Yes (JS-only) |