Sycamore - A reactive library for creating web apps in Rust and WebAssembly

Overview

Sycamore

Crates.io docs.rs GitHub contributors Discord

What is Sycamore?

Sycamore is a modern VDOM-less web library with fine-grained reactivity.

  • Lightning Speed: Sycamore harnesses the full power of Rust via WebAssembly, giving you full control over performance.
  • Ergonomic and Intuitive: Write code that feels natural. Everything is built on reactive primitives without a cumbersome virtual DOM.
  • No JavaScript: Had enough of JavaScript? So have we. Create apps using Sycamore without touching a single line of JS.

Documentation

Sycamore is extensively documented:

Still have questions? Don't hesitate to stop by our friendly Discord server.

Examples

Sycamore has many examples for your reference in the examples/ directory. Be sure to cheek them out!

Viewing on sycamore-rs.netlify.app

All the examples are hosted under sycamore-rs.netlify.app/examples/<example_name> with <example_name> being the name of the example you want to view. For instance, the hello example is hosted on sycamore-rs.netlify.app/examples/hello.

Building Locally

All the examples can also be built locally using Trunk. For instance, the following command builds and serves the hello example:

cd examples/hello
trunk serve

Now open up localhost:8080 in your browser to see "Hello World!".

Perseus

Perseus is a fullstack framework built with Sycamore. Think NextJS or SvelteKit but with no JavaScript. Everything from backend to frontend is built with pure Rust!

Alternatives?

Don't think Sycamore is for you? Thankfully, there are plenty of alternatives!

  • SolidJS: A declarative, efficient and flexible JavaScript library for building user interfaces
    Solid is a JavaScript library which greatly inspired Sycamore. Many concepts such as fine-grained reactivity and components as factory functions were borrowed from Solid. If you don't mind working with JavaScript (or TypeScript), go check it out!

  • Yew: Rust / Wasm framework for building client web apps
    Yew was also a big inspiration for Sycamore. Yew employs a VDOM and has a MVU (Elm) architecture. If you think that's for you, take a look!

  • MoonZoon: Rust Fullstack Framework
    MoonZoon also champions the no VDOM paradigm and uses dominator as its underlying DOM layer. MoonZoon is a fullstack framework making it easier to combine frontend and backend code with minimal boilerplate.

Contributing

Sycamore would not have been possible without the wonderful contributions from the community. Thank you!

Comments
  • Some performance tweaks

    Some performance tweaks

    Optimizations in sycamore-reactive crate.

    Some notable changes:

    • Simplify and reduce allocations in map_keyed and map_indexed.
    • Make Signal::trigger_subscribers slightly faster.
    performance 
    opened by lukechu10 10
  • Make `map_indexed` and `map_keyed` more idiomatic

    Make `map_indexed` and `map_keyed` more idiomatic

    Right now, map_indexed and map_keyed use a lot of index manipulations. This is not very idiomatic in Rust.

    Preferably, most of it can be refactored to use iterators instead. This will improve maintainability and perhaps even performance because it will remove the need for bound checks.

    good first issue 
    opened by lukechu10 10
  • Builder Pattern API

    Builder Pattern API

    Proposal

    I have been contemplating what a builder pattern API, as mentioned in #265, might look like. I personally like the idea of having both API's, and having the interop, as macros have their place which can be much easier to read, but the primary advantages, in my opinion to a builder pattern is that, currently, formatting and type hints don't work with the current tooling (rust-analyzer), and certain more complicated logic is not possible at the moment, without further syntax extensions.

    Also, from a discord comment, @lukechu10 mentioned the aim of eventually supporting React Native, and possibly other rendering targets. This to me, presents two different routes that could be taken:

    1. Having a rendering-agnostic API
    2. Having a rendering-specific API

    The first option could be something as follows (for HTML):

    button();
    div();
    a();
    /* etc */
    
    

    Whereas the agnostic approach could be something like:

    node("button");
    node("div");
    node("a");
    
    

    These features could be held behind a feature flag, such as html, react-native, native-script, etc. for the render-specific API, or just builder-api for the agnostic API, and prefixed with experimental: until an API is stabilized.

    Main required features

    In no particular order. Also note that all of the mentioned functions would be implemented for the builder struct and take either &mut self or self and return their respective Self type, but have been omitted for brevity..

    • (Un)setting Attributes

      • A further distinction could be made (for memory and performance reasons) between static and dynamic attributes, such as:

        fn set_attribute(name: &str, value: impl Into<JsValue>);
        
        // The Option type is important here, as it can be used to automatically remove
        // the attribute when required.
        fn set_dyn_attribute(name: &str, value: StateHandle<Option<impl Into<JsValue>>>);
        
        // Also note that remove_attribute is not needed here, since it's handled in the
        // dynamic case and in static cases not needed.
        
    • (Un)setting properties

      • Same as above
    • (Un)setting classes

      • Once again, I recommend having a distinction between static and dynamic classes.

        fn add_class(class: &str);
        fn add_dyn_class(class: StateHandle<Option<&str>>);
        
    • Add/remove children

      • For setting children, we have some choices to make. We can accept Vec<GenericNode>, or Template, thought the latter is preferable. The question lies on how to handle dynamic children.

        fn add_children(children: Template<G>);
        
        // Perhaps dynamic children could be handled as follows
        fn add_dyn_children(children: StateHandle<Template<G>>);
        
    • Special shortcuts

      • fn id(id: &str)
      • fn style(name: &str, value: &str) or perhaps fn add_styles<K, V>(HashMap<K, V>) where K: Hash + AsRef<str>, V: AsRef<str> or something similar. along with their dynamic Signal accepting counterparts.
      • And possible others I've missed.
    • Event listeners

      fn add_event_listener(event: &str /* or typed Event */, handler: EventHandler);
      
      // When listen is false, the event handler won't be discarded, just not trigger until
      // listen is true again.
      fn add_dyn_event_listener(event: &str, handler: EventHandler, listen: StateHandle<bool>);
      
    • Refs

      fn ref(ref: NodeRef);
      
    • Binding

      • Each respective supported bindable property could be made, such as value, checked, and optional element specific binding can be made, such as group.

        fn bind_value(value: Signal<String>);
        fn bind_group(group: Signal<String>);
        /* etc */
        
      • Another very important note, especially with Web Components, binding to arbitrary attributes and properties is a must have, as a lot of components, it's the only way to get notified on changes witch aren't emitted as custom events.

      fn bind_custom_attribute(name: &str, Signal<impl Deserialize>);
      fn bind_custom_property(name: &str, Signal<impl Deserialize>);
      
    • Build

      • Finally, we need to build the node into a Template.

    Important note

    The above API would currently require using Template for instantiating components, but it could be mentioned in the docs that if macros would like to be completely omitted, then one could use Component::__create_component(props).

    Did I miss anything? Can anything be improved? Please don't be shy. The more the critique, the better we can make Sycamore, together.

    C-enhancement 
    opened by jquesada2016 9
  • Builder API

    Builder API

    I have not fully tested, nor do I think the current iteration has the right aesthetics, but I believe it's in the right direction! This is an implementation attempt for the builder API as mentioned in #268.

    C-enhancement A-builder 
    opened by jquesada2016 8
  • Need to be able to convert web_sys::Element to Template<G>

    Need to be able to convert web_sys::Element to Template

    This is important for interfacing with many JS libraries which create arbitrary elements or produce template strings. I was unable to implement IntoTemplate<G> due to the blanket implementation, so used instead the From trait. It should also be possible in the future to create the template node without needing a wrapper element, though could not find a way from reading through the source. Any tips would be appreciated.

    C-enhancement 
    opened by jquesada2016 8
  • Issues When Running

    Issues When Running

    I can't seem to get the Hello World example from the README running. I have updated my main.rs file and added the dependency to Cargo.toml, but when I run using trunk I get a long list of errors (see below).

    Environment

    • Maple: 0.4.x
    • WSL / Ubuntu 20.04.1 LTS

    Additional context I have updated trunk, wasm-pack-cli, Rust, and a few other dependencies I think are related, just in case.

    Here is the start of the output. The list goes on for quite a while longer.

    โฏ trunk serve --open
    Apr 01 07:16:47.612  INFO ๐Ÿ“ฆ starting build
    Apr 01 07:16:47.616  INFO spawning asset pipelines
    Apr 01 07:16:47.775  INFO building maple-test
       Compiling js-sys v0.3.49
       Compiling console_error_panic_hook v0.1.6
    error: expected `,`
      --> /home/googlemac/.cargo/registry/src/github.com-1ecc6299db9ec823/console_error_panic_hook-0.1.6/src/lib.rs:80:43
       |
    80 |             #[wasm_bindgen(js_namespace = console)]
       |                                           ^^^^^^^
    
    error[E0433]: failed to resolve: use of undeclared type `Error`
       --> /home/googlemac/.cargo/registry/src/github.com-1ecc6299db9ec823/console_error_panic_hook-0.1.6/src/lib.rs:106:21
        |
    106 |             let e = Error::new();
        |                     ^^^^^ not found in this scope
        |
    help: consider importing one of these items
        |
    71  | use std::error::Error;
        |
    71  | use std::io::Error;
        |
    71  | use wasm_bindgen::__rt::core::fmt::Error;
        |
    
    error[E0425]: cannot find function `error` in this scope
       --> /home/googlemac/.cargo/registry/src/github.com-1ecc6299db9ec823/console_error_panic_hook-0.1.6/src/lib.rs:117:13
        |
    117 |             error(msg);
        |             ^^^^^ not found in this scope
    
    error: aborting due to 3 previous errors
    
    Some errors have detailed explanations: E0425, E0433.
    For more information about an error, try `rustc --explain E0425`.
    error: could not compile `console_error_panic_hook`
    
    To learn more, run the command again with --verbose.
    warning: build failed, waiting for other jobs to finish...
    error: expected `,`
       --> /home/googlemac/.cargo/registry/src/github.com-1ecc6299db9ec823/js-sys-0.3.49/src/lib.rs:639:39
        |
    639 |         #[wasm_bindgen(js_namespace = Atomics, catch)]
        |                                       ^^^^^^^
    
    error: expected `,`
       --> /home/googlemac/.cargo/registry/src/github.com-1ecc6299db9ec823/js-sys-0.3.49/src/lib.rs:649:39
    
    C-bug 
    opened by parker-codes 8
  • Backend Abstraction

    Backend Abstraction

    Fixes #66. I'm leaving for a week in 2 days, but I just spent an hour or two working on this today, and I'll probably do a little more tomorrow. Feel free to build on this or just do something else completely.

    This introduces a new trait, GenericNode. Right now, it only has one implementation, which is a real DOM node. I'm writing this in a way so that users will have to make their components generic, but will hopefully never have to specify what that generic type is because it'll be inferred from calling render().

    Right now, I have the following questions I'll need to answer to go further:

    • Handling next_sibling and parent_node functions. When those just call JS functions, it's no problem because it has a full GC that can handle cyclic references. Although that's possible in Rust with some work, it would be more efficient if we could remove calls to those functions. I could also make those return an error server-side (they're only used for modifying the state), but it would make modifying the data impossible server-sideโ€”meaning you can't have some async computation render stuff later, or if you did, it'd have to be implemented differently.
    • NodeRef: How to do this in a user-friendly way: do we force the user to downcast to a concrete type? It would be nice to not hardcode it being a web_sys::Node, for use cases like React Native. However, there is probably no need for it to work on the server.
    C-enhancement A-SSR 
    opened by lights0123 8
  • (Runtime) Templates

    (Runtime) Templates

    Closes #19

    Adds a template system where Template represents the structure of the view! with holes inside. These holes can then be binded to and filled in with the dynamic values.

    This should give a big performance boost on the client side because we are cloning templates now instead of creating each and every element individually. This could also give a performance boost on server-side by allowing us to cache the SSR-ed strings.

    This also unlocks other exciting features such as some form of hot view-reloading.

    C-enhancement performance 
    opened by lukechu10 7
  • Fix removing old nodes from parent

    Fix removing old nodes from parent

    Fixes #427

    The #427 bug was introduced in #416 inside the reconcile_fragments function.

    The quick fix was to add the negation that got dropped during that change - this seems to have caused the bug.

    ~I instead extracted the removal of nodes from the parent node part of the reconcile_fragments function to a new function and added tests for this new function to avoid any future regressions.~

    ~The tests use a pretty rough/bare bones mock of a GenericNode in order to satisfy the trait bounds required by the extracted function. I think the tests are worth the added file noise of the mock but let me know if you'd prefer I remove it (and probably the extracted function at that point).~

    opened by mc1098 7
  • An HTTP request example and a tailwindcss styling example

    An HTTP request example and a tailwindcss styling example

    I created this example (since I could not find an existing one) to get a feel for the developer experience of using a crate like reqwasm and styling with TailwindCSS when using sycamore.

    This example makes a GET request to CountAPI that simply increments everytime you visit the page or refresh the page i.e. counting page visits. I picked this example since I just wanted to create a really simple HTTP request to fetch some json data and then be able to display that data which then further updates a Signal and resulting into updating the relevant component.

    This also includes a little styling with TailwindCSS since the docs here suggested that the styling part is still under works.

    To test, you can run trunk serve --open which should build everything and the serve the page.

    A-examples 
    opened by attriaayush 7
  • use_context inside a Router can't find context when used after route change

    use_context inside a Router can't find context when used after route change

    Describe the bug When use_context is called from inside a Router after a route change it can't find the context value anymore and panics.

    To Reproduce Use code in reproduction repo and click on link with built site.

    Expected behavior use_context should return the context.

    Environment

    • Sycamore: master (the repo uses 0.6.3)
    • Browser: Edge/Firefox
    • OS: Ubuntu 21.04

    Additional context As far as I can tell, the context itself isn't being dropped, it's just not being found after the route changes.

    When it panics, there's an extra scope being searched in use_context which is not created in the sycamore_reactive::context::create_context_scope function.

    C-bug 
    opened by Zyllian 7
Releases(0.8.2)
Owner
Sycamore
A reactive library for creating web apps in Rust and WebAssembly
Sycamore
A react-inspired UI library for building multimedia desktop apps with rust and vulkan.

narui A react-inspired UI library for building multimedia desktop apps with rust and vulkan. declarative UI with Ergonomics similar to React with hook

apertusยฐ - open source cinema 42 Jan 1, 2023
Build beautiful desktop apps with flutter and rust. ๐ŸŒ  (wip)

flutter-rs Build flutter desktop app in dart & rust. Get Started Install requirements Rust flutter sdk Develop install the cargo flutter command cargo

null 2k Dec 26, 2022
Automatically create GUI applications from clap3 apps

Automatically create GUI applications from clap3 apps

Michaล‚ Gniadek 340 Dec 20, 2022
A little wrapper I've written for creating UI screens from files for the BevyEngine.

UI Screens for BevyEngine This is a little thing I put together for creating simple UI screens using the BevyEngine. The idea is to define the screens

Greg Moller 3 Nov 19, 2022
A tool for creating egui Visuals (themes).

egui-visuals-utility A tool for creating egui Visuals (themes). The code is rather messy and might crash but it seems to work. To load the theme use s

null 7 Jan 13, 2023
๐Ÿ–ผ A Rust library for building user interfaces on the web with WebGL.

wasm-ui Hey! Welcome to my little experiment. It's a Rust library for building user interfaces on the web. You write the interface in Rust, and wasm-u

Harry 10 Dec 1, 2022
Build smaller, faster, and more secure desktop applications with a web frontend.

TAURI Tauri Apps footprint: minuscule performance: ludicrous flexibility: gymnastic security: hardened Current Releases Component Descrip

Tauri 56.3k Jan 3, 2023
Native Maps for Web, Mobile and Desktop

mapr Native Maps for Web, Mobile and Linux A map rendering library written in Rust. Example | Book | API | Chat in Matrix Space Project State This pro

MapLibre 942 Jan 2, 2023
A cross-platform GUI library for Rust focused on simplicity and type-safety

A cross-platform GUI library for Rust, inspired by Elm

Hรฉctor Ramรณn 17.5k Jan 8, 2023
A Rust library to parse Blueprint files and convert them into GTK UI files

?? gtk-ui-builder A Rust library to parse Blueprint files and convert them into GTK UI files Inspired by the Blueprint project Example 1 - blueprints

Observer KRypt0n_ 5 Oct 22, 2022
An Anime Game Launcher variant written on Rust, GTK4 and libadwaita, using Anime Game Core library

An Anime Game Launcher GTK The launcher variant written on Rust, GTK4 and libadwaita, using Anime Game Core library You could also try the main branch

An Anime Team 77 Jan 9, 2023
Honkers Launcher variant written on Rust, GTK4 and libadwaita, using Anime Game Core library

You could also try the main branch Development Folder Description ui Blueprint UI files ui/.dist UI files compiled by the blueprint src Rust source co

An Anime Team 9 Nov 2, 2022
Simple and portable (but not inflexible) GUI library in C that uses the native GUI technologies of each platform it supports.

libui: a portable GUI library for C This README is being written. Status It has come to my attention that I have not been particularly clear about how

Pietro Gagliardi 10.4k Dec 31, 2022
A tiny, neat C library that portably invokes native file open and save dialogs.

Native File Dialog A tiny, neat C library that portably invokes native file open, folder select and save dialogs. Write dialog code once and have it p

Michael Labbe 1.5k Dec 28, 2022
An idiomatic GUI library inspired by Elm and based on gtk4-rs

An idiomatic GUI library inspired by Elm and based on gtk4-rs. Relm4 is a new version of relm that's built from scratch and is compatible with GTK4 an

Aaron Erhardt 722 Dec 31, 2022
Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust.

Deno Deno is a simple, modern and secure runtime for JavaScript and TypeScript that uses V8 and is built in Rust. Features Secure by default. No file,

Derek Jones 2 Aug 13, 2022
An easy-to-use, 2D GUI library written entirely in Rust.

Conrod An easy-to-use, 2D GUI library written entirely in Rust. Guide What is Conrod? A Brief Summary Screenshots and Videos Feature Overview Availabl

PistonDevelopers 3.3k Jan 1, 2023
Rust bindings for the FLTK GUI library.

fltk-rs Rust bindings for the FLTK Graphical User Interface library. The FLTK crate is a crossplatform lightweight gui library which can be statically

Mohammed Alyousef 1.1k Jan 9, 2023
Idiomatic, GTK+-based, GUI library, inspired by Elm, written in Rust

Relm Asynchronous, GTK+-based, GUI library, inspired by Elm, written in Rust. This library is in beta stage: it has not been thoroughly tested and its

null 2.2k Dec 31, 2022