State
By default, all corvu primitives manage their state internally. This means that they handle their state themselves and you don’t need to pass any props/state to them.
corvu aims to be very customizable and provides various ways to control a primitive or access internal state. Let’s take a look at them. We’ll use the Dialog primitive as an example, but the same applies to all other primitives.
Controlled State Section titled Controlled State
The easiest way to control a primitive’s state is by passing your own defined state to its Root
component. Most of the time, this consists of a getter and setter property like in this example, where we control the open state of a dialog:
import Dialog from '@corvu/dialog'
import { createSignal } from 'solid-js'
const MyDialog = () => {
const [open, setOpen] = createSignal(false)
return (
<Dialog open={open()} onOpenChange={setOpen}>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Dialog.Content>
<Dialog.Label>Label</Dialog.Label>
</Dialog.Content>
</Dialog>
)
}
This allows you to use the open state anywhere in your code and alter it freely. The dialog will open and close accordingly.
Context Section titled Context
It’s also possible to access the context of every primitive. This allows you to get the internal state of a primitive from anywhere in your code, as long as it’s under the Root
component, where the context gets provided. Accessing the context of a dialog looks like this:
import Dialog from '@corvu/dialog'
import { createSignal } from 'solid-js'
const DialogRoot = () => {
return (
<Dialog>
<DialogContent />
</Dialog>
)
}
const DialogContent = () => {
const { open, setOpen } = Dialog.useContext()
return (
<>
<p>The dialog is {open() ? 'open' : 'closed'}</p>
<button onClick={() => setOpen(open => !open)}>
My own, custom trigger button
</button>
<Dialog.Content>
<Dialog.Label>Label</Dialog.Label>
</Dialog.Content>
</>
)
}
Every primitive provides different properties in its context, have a look at the API section of each primitive to see what’s available.
Children callbacks Section titled Children callbacks
The Root
component of every primitive (and in a few cases others) also accepts a function as its children. By doing this, we can pass the internal state to the children for you to access. An example of this looks like this:
import Dialog from '@corvu/dialog'
import { createSignal } from 'solid-js'
const MyDialog = () => {
return (
<Dialog>
{(props) => (
<>
<p>The dialog is {props.open() ? 'open' : 'closed'}</p>
<button onClick={() => props.setOpen(open => !open)}>
My own, custom trigger button
</button>
<Dialog.Trigger>Open Dialog</Dialog.Trigger>
<Dialog.Content>
<Dialog.Label>Label</Dialog.Label>
</Dialog.Content>
</>
)}
</Dialog>
)
}
Note that the props passed from the Root
component include reactive getters. Make sure to access them in a reactive scope, like you would in any other Solid component.
Keyed context Section titled Keyed context
There may be situations where you want to use nested instances of the same primitive. For example, multiple dialogs with multiple trigger buttons that are hard to separate in the template. For this case, corvu allows you to pass a contextId
to every primitive component to tell which context to use.
Here’s how two nested dialogs would look like:
<Dialog contextId="dialog-1">
<Dialog contextId="dialog-2">
<Dialog.Trigger contextId="dialog-1">Open Dialog 1</Dialog.Trigger>
<Dialog.Trigger contextId="dialog-2">Open Dialog 2</Dialog.Trigger>
<Dialog.Content contextId="dialog-1">
<Dialog.Label contextId="dialog-1">Dialog 1</Dialog.Label>
</Dialog.Content>
<Dialog.Content contextId="dialog-2">
<Dialog.Label contextId="dialog-2">Dialog 2</Dialog.Label>
</Dialog.Content>
</Dialog>
</Dialog>
When using keyed contexts, you can pass the same key to the useContext()
function to access the context of the respective primitive.
const { open, setOpen } = Dialog.useContext('dialog-1')
Developed and designed by Jasmin