Golang SSR-first Frontend Library



Library that brings frontend-like components experience to the server side with native html/template on steroids. Supports any serving basis (net/http/gin/etc), that provides io.Writer in response.

License Go Report Card Go Reference

This project in early development, don't use in production! In case of any issues/proposals, feel free to open an issue

Why I need this?

  • Get rid of spaghetti inside of handlers
  • Organize code into configurable components structure
  • Simple and straightforward page rendering lifecycle
  • Asynchronous DTO without goroutine mess
  • Built-in dynamics like Hotwire or Laravel Livewire
  • Everyting on top of well-known html/template
  • Get control over project setup: 0 external dependencies, just kyoto itself

Why not?

  • In active development (not production ready)
  • Not situable for pretty dynamic frontends
  • You want to develop SPA/PWA
  • You're just feeling OK with JS frameworks


As simple as go get github.com/yuriizinets/kyoto
Check documentation page for quick start: https://kyoto.codes/getting-started.html


Kyoto project setup may seem complicated and unusual at first sight.
It's highly recommended to follow documentation while using library: https://kyoto.codes/getting-started.html

This example is not completely independent and just shows what the code looks like when using kyoto:

package main

import (


type PageIndex struct {
	Navbar kyoto.Component

func (p *PageIndex) Template() *template.Template {
	return mktemplate("page.index.html")

func (p *PageIndex) Init() {
	p.Navbar = kyoto.RegC(p, &twui.AppUINavNavbar{
		Logo: `<img src="/static/img/kyoto.svg" class="h-8 w-8 scale-150" />`,
		Links: []twui.AppUINavNavbarLink{
			{Text: "Kyoto", Href: "https://github.com/yuriizinets/kyoto"},
			{Text: "UIKit", Href: "https://github.com/yuriizinets/kyoto-uikit"},
			{Text: "Charts", Href: "https://github.com/yuriizinets/kyoto-charts"},
			{Text: "Starter", Href: "https://github.com/yuriizinets/kyoto-starter"},
		Profile: twui.AppUINavNavbarProfile{
			Enabled: true,
			Avatar: `
					<svg class="w-6 h-6 text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 8l7.89 5.26a2 2 0 002.22 0L21 8M5 19h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z"></path></svg>
			Links: []twui.AppUINavNavbarLink{
				{Text: "GitHub", Href: "https://github.com/yuriizinets/kyoto/discussions/40"},
				{Text: "Telegram", Href: "https://t.me/yuriizinets"},
				{Text: "Email", Href: "mailto:[email protected]"},


Documentation: https://kyoto.codes/
UIKit: https://github.com/yuriizinets/kyoto-uikit
Demo project, Hacker News client made with kyoto: https://hn.kyoto.codes/
Demo project, features overview: https://github.com/yuriizinets/kyoto/tree/master/.demo


Buy me a Coffee

Or directly with Bitcoin: bc1qgxe4u799f8pdyzk65sqpq28xj0yc6g05ckhvkk

  • Prototype: Multi-stage component UI update on Action

    Prototype: Multi-stage component UI update on Action

    Explore possibility to use server-sent events to deliver multiple UI updates.
    Logic must to be similar to "flush" functionality of ORM frameworks, something like kyoto.SSAFlush(p)

    Required knowledge:

    • SSE API (https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
    • SSA lifecycle theory and code (https://kyoto.codes/extended-features.html#ssa-lifecycle and https://github.com/yuriizinets/kyoto/blob/master/ext.ssa.go)
    • SSA communication layer code (https://github.com/yuriizinets/kyoto/blob/master/payload/src/dynamics.ts)

    Issue might be pretty hard to implement for people unfamiliar with project, but very interesting for those who want to explore project codebase.

    opened by yuriizinets 20
  • Prototype of functional way to define pages/components

    Prototype of functional way to define pages/components

    Current working prototype looks like this:

    func PageIndex(b *kyoto.Builder) {
    	b.Template(func() *template.Template {
    		return template.Must(template.New("page.index.html").ParseGlob("*.html"))
    	b.Init(func() {
    		b.State.Set("Title", "Kyoto in a functional way")
    		b.Component("UUID1", ComponentUUID)
    		b.Component("UUID2", ComponentUUID)
    func ComponentUUID(b *kyoto.Builder) {
    	b.Async(func() error {
    		// Execute request
    		resp, err := http.Get("http://httpbin.org/uuid")
    		if err != nil {
    			return err
    		// Defer closing of response body
    		defer resp.Body.Close()
    		// Decode response
    		data := map[string]string{}
    		// Set state
    		b.State.Set("UUID", data["uuid"])
    		// Return
    		return nil
    opened by yuriizinets 7
  • Component actions not being executed

    Component actions not being executed

    I have an action which I've defined on a component. The component code looks like this:

    package components
    import (
    type SignIn struct {
    	Context  *gin.Context
    	Username string
    	Password string
    	Errors   []string
    func (c *SignIn) Actions() ssc.ActionsMap {
    	return ssc.ActionsMap{
    		"DoSignIn": func(args ...interface{}) {
    			var configService service.ConfigService = service.ConfigurationService("")
    			if configService.Error() != nil {
    				log.Printf("Error while connecting to DB service. error=%s", configService.Error())
    				c.Errors = append(c.Errors, "Internal server error")
    			log.Printf("Triggered sign in")
    			var dbService service.DBService = service.SQLiteDBService("")
    			if dbService.Error() != nil {
    				log.Printf("Error while connecting to DB service. error=%s", dbService.Error())
    				c.Errors = append(c.Errors, "Internal server error")
    			var loginService service.LoginService = service.DynamicLoginService(dbService)
    			var jwtService service.JWTService = service.JWTAuthService()
    			var loginController controller.LoginController = controller.LoginHandler(loginService, jwtService)
    			c.Context.Set("Username", c.Username)
    			c.Context.Set("Password", c.Password)
    			session := service.NewSessionService(c.Context, false)
    			token := loginController.Login(c.Context)
    			session.Set("token", token)
    			err := session.Save()
    			if err != nil {
    				log.Printf("Error while saving session. error=%s", err)
    			log.Printf("Login successful. user=%s", c.Username)
    			c.Context.Redirect(http.StatusFound, "/")

    The template:

    {{ define "SignIn" }}
    <div {{ componentattrs . }}>
        <h1 class="title is-4">Sign in</h1>
        <p id="errorFeedback" class="help has-text-danger is-hidden">
            {{ .Username }} {{ .Password }}
        <div class="field">
            <div class="control">
                <input class="input is-medium" value="{{ .Username }}" oninput="{{ bind `Username` }}" type="text" placeholder="username">
        <div class="field">
            <div class="control">
                <input class="input is-medium" value="{{ .Password }}" oninput="{{ bind `Password` }}" type="password" placeholder="password">
        <button onclick="{{ action `DoSignIn` `{}` }}" class="button is-block is-primary is-fullwidth is-medium">Submit</button>
        <br />
        <small><em>Be nice to the auth system.</em></small>
    {{ end }}

    and is included like this:

                    <div class="column sign-in has-text-centered">
                        {{ template "SignIn" .SignInComponent }}

    Where the component inclusion looks like this:

    package frontend
    import (
    type PageSignIn struct {
    	ctx             *gin.Context
    	SignInComponent ssc.Component
    func (p *PageSignIn) Template() *template.Template {
    	return template.Must(template.New("page.signin.html").Funcs(ssc.Funcs()).ParseGlob("frontend/new_templates/*/*.html"))
    func (p *PageSignIn) Init() {
    	p.SignInComponent = ssc.RegC(p, &components.SignIn{
    		Context: p.ctx,
    func (*PageSignIn) Meta() ssc.Meta {
    	return ssc.Meta{
    		Title:       "Test kodah's blog",
    		Description: "Test description",
    		Canonical:   "",
    		Hreflangs:   nil,
    		Additional:  nil,

    When I run the DoSignIn action it is not executed though;

        <button onclick="{{ action `DoSignIn` `{}` }}" class="button is-block is-primary is-fullwidth is-medium">Submit</button>

    I realize there's not a lot of documentation but I went off of the examples and this seems right.

    opened by kodah 7
  • Using ParseFS and embed.FS

    Using ParseFS and embed.FS

    I've been trying to figure out a pattern to use embed.FS and template.ParseFS for delivering the HTML files

    Do you have any examples for this? I've been struggling with a couple of different errors and including the Funcs with the parsed templates

    template: \"templates/pages.home.html\" is an incomplete or empty template

    	//go:embed templates
    	Templates embed.FS
    	return template.Must(
    		template.New("templates/pages.home.html").Funcs(kyoto.TFuncMap()).ParseFS(assets.Templates, "templates/pages.home.html"),
    opened by aranw 6
  • Up-to-date on Using the UIKit

    Up-to-date on Using the UIKit

    Hi guys,

    First of all, just wanted to take a moment and express my gratitude to your guys for making Kyoto a reality. It's awesome and really makes a lot sense for gophers to build out frontends on the fly. That said, I was wondering if you guys had any updated docs on using the UIKit. So far all the docs and demo projects I've come across were on an older version of the codebase and the apis have changed quite a bit since then. Would love some guidance here. Thanks in advance.

    Best, Jay

    opened by jim380 3
  • It is not possible to use `render.Custom` per component

    It is not possible to use `render.Custom` per component

    Each render.Custom call overrides global context. With this approach it wouldn't be possible to define custom rendering on a component level.
    As an option, we can store this in the state as internal, helpers.ComponentSerialize will remove it on state serialization.

    bug good first issue 
    opened by yuriizinets 3
  • Better Actions protocol implementation

    Better Actions protocol implementation

    Current approach is far from ideal. State and arguments are passed in SSE query, response must to be base64 encoded to avoid newlines issue (which increases the size of the response).

    Websockets cannot be considered:

    • They don't scale well (in case of keeping connection alive all the time)
    • Sometimes it requires special configuration of networking, especially on big projects
    • In some countries/hotels/public places you can see ports/protocols whitelisting, which immediately kills this approach
    enhancement good first issue 
    opened by yuriizinets 3
  • Support `tinygo` compiler

    Support `tinygo` compiler

    tinygo may provide a lot of benefits to the project, like compiling to smaller wasm payload and using in places where payload size is critical. I also consider as an option using kyoto for creating frontend, rendered on the Edge Network (f.e. Cloudflare Workers). Workers have a lot of limitations and tinygo may satisfy them.

    enhancement hardcore 
    opened by yuriizinets 3
  • Passing Go packages to Pages/Components

    Passing Go packages to Pages/Components

    Been playing around with Kyoto and really liking the pattern once I managed to get my head around it

    But now I'm starting to wonder what are the best practices for passing Go packages to Pages/Components seen as the handlers create a new instance of the page on each page load it's not possible to pass in a dependency inside the Page/Component structs

    One way I've managed to do this is passing it into the Context but I don't really want to fill up my context with lots of dependencies but I feel like there must be a nicer way of doing this that is more scalable?

    opened by aranw 3
  • Question - set cookie on response to SSA call

    Question - set cookie on response to SSA call

    How is it possible to access the request context from a call to a Server-Side Action. Say, for instance you want to set a cookie in the response to an SSA call.

    In the example demo app for the form submission example (email validator) you have the following:

    type ComponentDemoEmailValidator struct {
    	Email   string
    	Message string
    	Color   string
    func (c *ComponentDemoEmailValidator) Actions() ssc.ActionMap {
    	return ssc.ActionMap{
    		"Submit": func(args ...interface{}) {
    			if emailregex.MatchString(c.Email) {
    				c.Message = "Provided email is valid"
    				c.Color = "green"
    			} else {
    				c.Message = "Provided email is not valid"
    				c.Color = "red"

    I am aware you can create an "Init" method function to access the request context i.e.

    func (c *ComponentDemoEmailValidator) Init(p ssc.Page) {
        c.Page = p
        r := ssc.GetContext(p, "internal:r").(*http.Request)
        rw := ssc.GetContext(p, "internal:rw").(http.ResponseWriter)

    But how do you access the request/response context from within the "Actions()" method so that you can, for example, set a cookie in the response. Is this possible?

    opened by c-nv-s 3
  • Interaction with complex state across different adapters is uncomfortable

    Interaction with complex state across different adapters is uncomfortable

    In the struct mode it's much easier to initialize nested components and interact with them in next lifecycle steps. In case of func mode (which is default now) we need to interact with kyoto.Store instance, which is OK for simple state, but interaction with nested components is awful. You need to understand how Core.Component works and use explicit type casting.

    Needs to figure out, how to simplify work with components.

    opened by yuriizinets 2
  • Server Side State

    Server Side State

    Will be useful in case of large state payloads.
    Instead of saving state inline as html tag, store state on server side and inject state hash as html tag.
    This feature will decrease amount of data, sent with SSA request and total HTML document size.

    Key requirements:

    • Implement at least in-memory storage
    • Support for multiple state storages (with interface)
    • Component-level storage configuration (inline or server-side)
    opened by yuriizinets 2
  • v1.0.2(Jun 28, 2022)

  • v1.0.1(Jun 27, 2022)

  • v1.0.0(Jun 26, 2022)

    A first major release of kyoto, v1.0.0. We went through a huge architecture changes multiple times and took some hard decisions in development process. Please note, it’s a breaking release. It’s not similar to anything published in 0.x versions.

    Key concept of the new architecture comparing to struct based components - asynchronous functions as a component, based on generics and zen.Future. As far as overall concept is not documented yet, I’d recommend checking code sources for now. It’s well documented and structured.

    There is no sense to provide a change list because everything was changed drastically, so I’d like to recommend checking our documentation on https://pkg.go.dev/github.com/kyoto-framework/kyoto. 

As a part of our optimizations, we are moving our documentation directly into the code. Documentation will be automatically generated by pkg.go.dev, which would significantly ease the overall development process.

    I have to apologize for drastically changing architecture right before 1.0. This decision should have been made before the release because stable version imposes many restrictions on such movements. Sticking with not-so-good approach for compatibility with 0.x (which did not promise to stay stable anyway) is quite a bad idea. Work on minor libraries refactor, like uikit, will start right from this moment.

    If you find yourself in a bad situation because of these changes, please, let me know. I can help with adapting to this change, as our team will be doing the same. You can find contacts right in the README.

    Source code(tar.gz)
    Source code(zip)
  • v0.3.2(May 4, 2022)

  • v0.3.1(May 4, 2022)

  • v0.3.0(Apr 14, 2022)

    This is the last release before 1.0 will be released. It was created as a transfer point between old and new architecture. Complete notes about changes will be posted with 1.0 release.

    Source code(tar.gz)
    Source code(zip)
  • v0.2.0(Dec 25, 2021)

    I am pleased to present a second release of this library! We are moving slowly, but every step is quite important. It proves this "concept" is no longer just a concept. Let's take a closer look at the changes this release brings!


    • Multi-stage UI update on action (related issue https://github.com/kyoto-framework/kyoto/issues/62). Awesome feature, proposed by @bketelsen that allows to push multiple UI updates during single action call. Useful thing to show current status/step of a long-running action. Documentation.
    • ssa:oncall.display control attribute (related issue https://github.com/kyoto-framework/kyoto/issues/56). Changes display parameter during action call, at the end of an action the layout will be restored. Documentation
    • ssa:onload trigger attribute (related issue https://github.com/kyoto-framework/kyoto/issues/63). Provides a way to trigger an action on page load. This may be useful for components' lazy loading. Documentation
    • ssa:poll + ssa:poll.interval trigger attributes (related issue https://github.com/kyoto-framework/kyoto/issues/18). Provides a way to trigger an action periodically. Useful for components that have to be updated over time (f.e. charts, stats, etc.). Documentation
    • ssa:onintersect trigger attribute (related issue https://github.com/kyoto-framework/kyoto/issues/36). Provides a way to trigger an action on element intersection. Documentation
    • ssa:render.mode control attribute (related issue https://github.com/kyoto-framework/kyoto/issues/70). Determines which mode to use for dynamic DOM updating. Currently, 2 modes are supported: "morphdom" and "replace". Documentation
    • ssa.morph.ignore and ssa.morph.ignore.this control attributes (related issue #https://github.com/kyoto-framework/kyoto/issues/43). Ignore elements morphing (with or without children). Documentation is not ready yet
    • The possibility of using custom render method (related issue https://github.com/kyoto-framework/kyoto/issues/42). It's an important step to eliminate obligatory using of html/template and give more control to developers. Documentation
    • Support ndjson (newline delimited json) output format for Insights feature (related issue https://github.com/kyoto-framework/kyoto/issues/49). Documentation is not ready yet.
    • Option for changing SSA endpoint (related issue https://github.com/kyoto-framework/kyoto/issues/84). Documentation is not ready yet.
    • Option for changing async error behavior (related issue https://github.com/kyoto-framework/kyoto/issues/77). Documentation is not ready yet


    Nothing in this release :) But old deprecated functions from 0.1 are cleaned up.

    Future plans

    • Video tutorials and articles. It's not enough to have a documentation as far as it's not providing step-by-step usage guide, also some people better understand information with audio/video content.
    • More attention to minor things, like UI Kit and starter project.
    • Refactor rendering lifecycle architecture (related issue https://github.com/kyoto-framework/kyoto/issues/93). Lifecycle is pretty similar to pipeline, so job execution system (https://github.com/kyoto-framework/scheduler) perfectly fits for this purpose.
    • Functional way to define pages and components (related issue https://github.com/kyoto-framework/kyoto/issues/94).
    • Server side state (related issue https://github.com/kyoto-framework/kyoto/issues/28).
    • Support tinygo compiler (related issue https://github.com/kyoto-framework/kyoto/issues/80). An important step on the road to Edge Workers.
    • Cover project with tests (related issue https://github.com/kyoto-framework/kyoto/issues/53).

    Final words

    I would like to mention and say thanks to this people:

    • @RowdyHcs for active participation in project development
    • @bketelsen for providing ssa:poll pull request, minor improvements and idea of multi-stage UI update
    • @OpenSauce for detailed documentation review for grammar mistakes
    • @inthepanchine for ndjson insights output
    • ... and other people can be found here
    Source code(tar.gz)
    Source code(zip)
  • v0.1.4(Dec 8, 2021)

  • v0.1.3(Dec 2, 2021)

  • v0.1.2(Nov 28, 2021)

  • v0.1.1(Nov 26, 2021)

  • v0.1.0(Nov 1, 2021)

    First alpha release is here!
    It was a log way from concept to actual implementation, and we are happy what we got now. Now we want to make first alpha release to fix current state and set of features before providing more changes. 0.2 version will bring some changes, some of them may be breaking, so 0.1 version is a "stable" release for people who already using this library.

    Overall status

    This table represents the current state of things in the library

    | Feature | Status | Description | |-------------------|-------------|-------------------------------------------------| | Page rendering | Stable | Server side rendering with components lifecycle | | Built-in handler | Stable | High-level page handler for net/http | | Context | Stable | Global page-level context | | SSA | Unstable | Page dynamic behavior with Server Side Actions | | Insights | Unstable | Rendering and lifecycle timings | | Meta builder | Unstable(!) | Simple way to build page meta | | Server Side State | Planned | Save state on the server side instead of client |

    Future plans

    In the 0.2 we are going to:

    • Improve contribution experience. Now, it's pretty hard to find good issues for external contributors
    • Standardize SSA attributes naming rules
    • Introduce to SSA more features like loading state
    • Get rid of obligatory using html/template, provide an ability to choose own render engine
    • Provide component interface to support Render method, where developer can define own way to render component


    We changed some references during developer to be more understandable, but also we created aliases to be backward compatible. We are going to remove them in 0.2.
    Also, we found some things that we created are overcomplicated, so we created easier to use analogs. Old functions are still in the codebase, but will be removed on 0.2.

    • kyoto.Funcs - use kyoto.TFuncMap instead
    • kyoto.PageHandlerFactory - use opinionated kyoto.PageHandler or create own generic handler
    • kyoto.SSAHandlerFactory - use opinionated kyoto.SSAHandler or create own SSA handler

    Final words

    I'd like to thank all the people who supported the project with contributions, or even used the library for own projects!
    But as a gentle reminder, please, avoid using this in production for now :)

    Source code(tar.gz)
    Source code(zip)
Yurii Zinets
Software Engineer
Yurii Zinets
ARM project repository for back-/frontend dev

Ahlam Rahma Mohamed (ARM) Project This repository will include the code base for the ARM project user interface and other helping components. Author M

null 0 Dec 17, 2021
Default godoc generator - make your first steps towards better code documentation

godoc-generate Overview godoc-generate is a simple command line tool that generates default godoc comments on all exported types, functions, consts an

Dimitar Petrov 18 Nov 14, 2021
Code snippets by first time open source contributors

Introduction Golang code snippets by first time open source contributors Rules How to contribute Add a folder and create your desired code snippet fil

Luigi Morel 1 Oct 6, 2021

Generate FIRST/FOLLOW/PREDICT Set from BNF. We can use it to study parser theory. Feature FirstSet generate. Output pretty. FollowSet generate. Output

imtf 1 Oct 30, 2021
Library to work with MimeHeaders and another mime types. Library support wildcards and parameters.

Mime header Motivation This library created to help people to parse media type data, like headers, and store and match it. The main features of the li

Anton Ohorodnyk 28 Jul 25, 2022
GoLang Library for Browser Capabilities Project

Browser Capabilities GoLang Project PHP has get_browser() function which tells what the user's browser is capable of. You can check original documenta

Maksim N. 41 Jul 22, 2022
Type-safe Prometheus metrics builder library for golang

gotoprom A Prometheus metrics builder gotoprom offers an easy to use declarative API with type-safe labels for building and using Prometheus metrics.

Cabify 93 Jun 9, 2022
Simple licensing library for golang.

license-key A simple licensing library in Golang, that generates license files containing arbitrary data. Note that this implementation is quite basic

Hyperboloide 251 Jul 25, 2022
A Golang library to manipulate strings according to the word parsing rules of the UNIX Bourne shell.

shellwords A Golang library to manipulate strings according to the word parsing rules of the UNIX Bourne shell. Installation go get github.com/Wing924

Wei He 17 Mar 15, 2022
Flow-based and dataflow programming library for Go (golang)

GoFlow - Dataflow and Flow-based programming library for Go (golang) Status of this branch (WIP) Warning: you are currently on v1 branch of GoFlow. v1

Vladimir Sibirov 1.4k Jul 30, 2022
a Go (Golang) MusicBrainz WS2 client library - work in progress

gomusicbrainz a Go (Golang) MusicBrainz WS2 client library - a work in progress. Current state Currently GoMusicBrainz provides methods to perform sea

Michael Wendland 45 May 3, 2022
ghw - Golang HardWare discovery/inspection library

ghw - Golang HardWare discovery/inspection library ghw is a small Golang library providing hardware inspection and discovery for Linux and Windows.

Jay Pipes 1.2k Jul 30, 2022
GoLang Library for Browser Capabilities Project

Browser Capabilities GoLang Project PHP has get_browser() function which tells what the user's browser is capable of. You can check original documenta

Star Inc. 0 Nov 23, 2021
A WSL Library for Golang.

wsllib-go A WSL Library for Golang. Usage Get this package go get

yuk7 4 Jun 13, 2022
Go-linq - A powerful language integrated query (LINQ) library for Golang

go-linq A powerful language integrated query (LINQ) library for Go. Written in v

Ahmet Alp Balkan 3k Aug 1, 2022
libFFM-gp: Pure Golang implemented library for FM (factorization machines)

libFFM-gp: Pure Golang implemented library for FM (factorization machines)

null 0 Jan 23, 2022
Sa818 - Sa818 UHF/VHF walkie talkie module control library for golang

SA818 golang library for serial control This library written in Go programming l

Suvir Kumar 0 Jan 23, 2022
The Webhooks Listener-Plugin library consists of two component libraries written in GoLang

The Webhooks Listener-Plugin library consists of two component libraries written in GoLang: WebHook Listener Libraries and Plugin (Event Consumer) Libraries.

Temur Yunusov 0 Feb 3, 2022
Evolutionary optimization library for Go (genetic algorithm, partical swarm optimization, differential evolution)

eaopt is an evolutionary optimization library Table of Contents Changelog Example Background Features Usage General advice Genetic algorithms Overview

Max Halford 804 Aug 1, 2022