Introduction
The introduction will focus on the general answer to How to share state among components in Astro? The solution section will focus on how to sync client and server components with cookies in Astro.
Sharing states and events among client components
- Framework : Front End Frameworks such as Vue, Solid, Preact,... do handle components state sharing
- Library : for a solution that can be used without a commitment to a given Framework see https://github.com/nanostores/nanostores more details about this in Astro Docs https://docs.astro.build/en/core-concepts/sharing-state/
- vanilla js (states only) : as simple as module global var (as reminded by user SP33D). note exporting a variable is possible, but exporting a function is a more desirable pattern
const devices = {
poster:{}
}}
function get_devices(){
return devices
}
export{
get_devices
}
full project example https://github.com/MicroWebStacks/astro-home-control/blob/2107f94d0ba9ca76b43777d8ca24eae99b3e78cc/src/libs/power_state.js#L7
Sharing states and events with vanilla js
- Vanilla js : it is also possible to use custom events between client components where the html element is the target of the event like in this example
...
event(panel,"update",data[name])
...
element.addEventListener("update",(event)=>{
panel_set_state(name,event.detail)
})
fulle project example : https://github.com/MicroWebStacks/astro-home-control/blob/2107f94d0ba9ca76b43777d8ca24eae99b3e78cc/src/pages/index.astro#L54
Sharing State between Client and Server
Server to client through page reload
by embedding variables directly within the html tags or inside html attributes <p class="value">{init}</p>
(simplest and most common)
by using <script define:vars={{init}}>
This could be part of the solution but it does not handle the client->server back link and comes with disadvantages
the passed variable will get hardcoded in the script which becomes specific to the component instance (if you have 10 components, you get 10 scripts each in the body with the corresponding component instance value !!!)
This is how it is translated

as consequence, the script is inline, no more bundling, late loading (not in a head asset anymore)
no caching, fetched in every page,...
Server to client without page reload
For dynamically server changing variables, Server Sent Events can be used https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events
I will not detail it here as it is not needed for this question, but it can be used with Astro and an example can be found here https://github.com/MicroWebStacks/astro-examples#03_sse-counter
Within the same scope websockets can be used as well, but that starts to become over-dimentioned for the problem, if complexity is not an issue then also databases can be accessed from both client and server.
Server and Client persistence and sync
Using client storage
This is a possible solution that client persist his choice in storage, the disadvantages are
- flicker of server answer in case storage is only known to the client
- or more code to be developed to handle client side submission and server side endpoint capture, which needs to handle session and user management !!!
for those interested in the advanced example of flicker free state share with sessionStorage and url param here a working sample https://github.com/MicroWebStacks/astro-examples#14_client-storage-counter
Using cookies
This is the simplest way, see solution
Solution : how to sync client and server in Astro using cookies
The question post got the right investigation then got stuck on how to use cookies client side :
here is all it takes to set and get cookies with on the client, in few lines of vanilla javascript, no depndencies. See this question/answer Set cookie and get cookie with JavaScript
here minified and customized for a counter, but for expiry handling, see the referenced question
function get_counter(){
const entry = document.cookie.split(';').find(entry=>entry.replace(' ','').startsWith('counter='))
if(entry){
return parseInt(entry.split('=')[1])
}else{
return 0
}
}
function set_counter(counter){
document.cookie = `counter=${counter}`
console.log(`new counter value = ${counter}`)
}
Example of client side persistent counter
To make the example simpler, I used a counter instead of language
here a full example
server side cookie usage
in Astro, the counter cookie can be used as follows
let counter = 0
const cookie = Astro.cookies.get("counter")
if(cookie?.value){
counter = cookie.value
}
console.log(`index.astro> cookie counter = ${counter}`)
Potential issues
- It is important to ensure that cookies are passing through in the deployment host, as that can be an issue that prevents this solution, it is possible to check that in the example with server console log