# Introduction Spair is a Rust frontend framework. Compare to other frameworks in Rust, Spair is both small and fast. Spair is possibly the weirdest framework in Rust frontend ecosystem. Spair is neither vDOM, nor reactive. But Spair provides features similar to **both** pure-vDOM (without using hooks) and reactive frameworks. The two modes are called *incremental-render* (pure-Spair, or simply Spair for short if not causing confusion) and *queue-render* (Spair-qr). Both modes can be used in the same component. There are more weirdnesses wait for you if you dive into Spair. But I think it's worth it because Spair is able to reach high performance without having to deal with things like hooks, or signals. If pure-Spair performance is not enough, Spair-qr can help a bit more in performance. In performance, pure-Spair is significant faster than Yew, React and comparable to [Dominator] and [Sycamore]. Spair-qr is comparable to Leptos and Solid-store. In size, Spair produces smaller `.wasm` file than all of Rust frameworks mentioned above (Yew, Dominator, Sycamore and Leptos). You can always start to build your components with pure-Spair (it's easy to work with, but still very fast). Then, if there are some performance issues, you can introduce queue-render to the problem parts of your components. It means that just some critical parts of your app works in queue-render mode. The remaining parts of the app still work in incremental mode. ## The `Hello World` app Spair is designed to make big single page applications (I think so, but I may be wrong). Therefore, it looks a bit overcomplicated with the Hello World exmaple. ```rust struct State { message: String, } impl spair::Component for State { fn render(&self, element: spair::Element) { // Render the value of `self.message` as a text in `element` // on the first render, and update it on subsequence renders element.rupdate(&self.message); } } // The root component is required to implement this, // child component is required to implement a different trait. impl spair::Application for State { fn init(_: &spair::Comp) -> Self { Self { message: "Hello World!".to_string(), } } } fn main() { State::mount_to_element_id("root_element_id"); // or, // State::mount_to_body(); } ``` ## Weirdnesses cause by incremental render Incremental render is the default mode in Spair. "Incremental render" means that Spair starts with an empty element in your browser and add elements to it on the first run, then modify those elements on subsequence runs. Therefore, Spair's render method will not return an element, but require an element passed to it. In the Hello World example, Spair will look for and element with `id="root_element_id"` and pass it to the `Component::render` method. The requirement of a pre-existing element applies to all pieces of render code. For example, you can define a method to render a button: ```rust fn render_button(button: spair::Element) { // Render the button here } ``` In the code above, `State` (in `spair::Element`) is the type of your component's state. Again, you can see the the `button` is required by `render_button`, so you have to use it like this: ```rust impl spair::Component for State { fn render(&self, element: spair::Element) { element.button(render_button); // ^^^^^^^^^^^^^ this is `fn render_button(spair::Element)` // ^^^^^^ `button` is a method that creates a `