It's React... but for C++!
GoatUI is a C++ library that allows you to create web-based user interfaces using components. It compiles your C++ code into WebAssembly, which runs in the browser to generate the UI.
-
Web-Based: Create interactive user interfaces that run in the browser using C++.
-
Cross-Platform: With WebAssembly, your GoatUI program can run across all modern browsers.
-
Reactive Components: Build your UI using components that automatically update when the state changes.
-
Event Handling: Handle events like button clicks and form submissions with ease.
- Emscripten: Install Emscripten to compile C++ to WebAssembly.
-
Clone the Repository:
git clone https://github.com/LehuyH/goatui.git
-
Include
goatui/component.hpp
: Add#include "goatui/component.hpp"
in your C++ project.
#include "goatui/component.hpp"
using namespace std;
Reactive<int> counter(0);
int main(){
Component app("div",{
new Component("button",{
new Attribute("class","bg-gray-200 hover:bg-gray-100 rounded p-4")
},{
EventListener("click",[](int){
counter = counter.getValue() + 1;
}),
},{
new r("This button has been clicked "), new s(counter), new r(" times")
}
)
});
app.mount();
}
GoatUI provides an easy-to-use API for creating web-based user interfaces using C++. Here's a quick overview of the main concepts:
Use the Component
class to create UI elements. Each component can have children components, attributes, and event listeners.
Component(string HTMLTag, vector<Attribute*> attributes, vector<EventListener*> eventListeners, vector<Component*> children)
You can omit attributes
, eventListeners
, or children
but the order must be preserved.
Here's an example of a simple component:
Component container("div", {
new Attribute("class", "flex items-center flex-col justify-center min-h-screen p-8 space-y-4")
}, {
// You can nest components inside other components
new Component("h1", {
// Add attributes to the component
new Attribute("class", "text-2xl")
}, {
new r("Hello, World!")
}),
new Component("button", {
new Attribute("class", "bg-blue-500 text-white p-2 rounded")
}, {
// Add event listeners to the component
EventListener("click", [](int) {
// Handle the event here
})
}, {
new r("Click me!")
})
});
To render the component, call the mount
method:
container.mount();
This will render the GUI in the browser:
By default, GoatUI's web executor includes UnoCSS with a TailwindCSS compatibility layer for styling. This means you can use any class from TailwindCSS to style your components.
However, this behavior can be modified by changing ./dist/index.html
to include your own CSS file.
You can use the r
class to render raw text and the s
class to render reactive values
new Component("h1",{
new r("Hello, World! The count is:"),
new s(counter)
});
With GoatUI's reactivty system, you can declarative create GUIs that automatically update when the state changes.
To create a reactive value, use the Reactive
class:
Reactive<int> counter(0);
Reactive<string> message("Hello, World!");
You can access the value of a reactive variable using the getValue
method:
int value = counter.getValue();
To update the value of a reactive variable, simply assign a new value to it:
counter = 42;
When a reactive variable is updated, any components that depend on it will automatically re-render.
To specify this relationship, you can use the s
class to create reactive components.
For example:
Component app("div",{
new Component("h1",{
new s(counter)
})
});
When the counter
value changes, the h1
element will automatically update to reflect the new value.
You can use ReactiveAttribute
to create reactive attributes too:
Reactive<string> inputValue("");
Component input("input",{
new ReactiveAttribute("value",inputValue)
});
This will create an input element that updates its value whenever inputValue
changes.
You can handle events like button clicks and form submissions using the EventListener
class.
The EventListener
class takes an event name and a callback function as arguments:
EventListener(string HTMLEvent, function<void(int)> callback)
The callback function takes an integer argument, which is a pointer to the value of the event.
Reactive<string> inputValue("");
Component input("input",{
new ReactiveAttribute("value",inputValue)
},{
EventListener("input",[](int valuePtr){
//When the user types in the input, update the reactive value
inputValue = std::string((char*)valuePtr);
})
});
This code creates an input element that updates the inputValue
reactive variable whenever the user types in the input.
To improve convenience and reusability, it is recommended to create custom components by deriving from the Component
class. This allows you to encapsulate common components that you use frequently.
We ship GoatUI with a standard UI kit that includes common components like buttons and inputs under goatui/ui-kit
.
Styled button component with hover and active states.
Example with ButtonPrimary
:
ButtonPrimary button("Click me!",[](int){
//Handle button click
});
A collection of styled input components.
Example with InputText
:
Reactive<string> inputValue("");
InputText("Type something",inputValue);
To compile and build your C++ code with GoatUI, follow these steps:
- Run the following command in your terminal:
em++ (ADD SOURCE FILES HERE) -s WASM=1 -o ./dist/main.js -s EXPORTED_RUNTIME_METHODS='[\"getValue\",\"ccall\"]' -s NO_EXIT_RUNTIME=1 -s DEFAULT_LIBRARY_FUNCS_TO_INCLUDE='$stringToNewUTF8' -sASYNCIFY -Wno-non-pod-varargs -s EXPORTED_FUNCTIONS=[\"_callEventListener\",\"_callEventListenerWithValue\"] -fexceptions
Replace (ADD SOURCE FILES HERE)
with any additional source files your project requires ex: main.cpp
-
This command will generate the necessary output in the
./dist
directory. -
You can then upload the contents of the
./dist
folder to any static hosting service to run your application.
GoatUI is licensed under the MIT License.