Slots
In GamefaceUI, you can customize parts of a component using slots. Slots act as placeholders within components, allowing you to insert custom content when the component is used. This approach provides flexibility for creating reusable components while enabling customization of specific parts.
Slots are special properties in a component that accept custom content and properties. They are defined in the component’s template and can be filled with any valid JSX or HTML content when the component is used.
How to use slot placeholders
Section titled “How to use slot placeholders”In the following example, the Button component includes a slot named Icon. This slot serves as a placeholder for adding custom icon content when the button is used. The Icon slot can also accept properties and children to customize its appearance and behavior.
const MyComponent = (props) => { return ( <Button> Button text <Button.Icon before> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M4 8H12M12 8L8 4M12 8L8 12" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </Button.Icon> </Button> );};Adding slots to your component
Section titled “Adding slots to your component”To add slots to your component, define them in the component’s template. Here’s an example of how to create slots.
Consider the following Button component:
interface ButtonProps { disabled: boolean}
const Button:ParentComponent<ButtonProps> = (props) => { return ( <div> <button disabled={props.disabled}> {props.children} </button> </div> );};
export default Button;To add an Icon slot to the Button component, use the createTokenComponent function from the src/components/utils/tokenComponents.tsx file. This utility helps create token slots that can be integrated into the component’s template. You can define the slot’s properties by passing their types to the createTokenComponent function. For instance, to define an Icon slot with a before property, you can do the following:
import { createTokenComponent } from '@components/utils/tokenComponents';
interface IconProps { before?: boolean;}
const Icon = createTokenComponent<IconProps>();Next, to make the Icon slot accessible via Button.Icon, assign it to the Button component:
import { createTokenComponent } from '@components/utils/tokenComponents';
interface IconProps { before?: boolean;}
const Icon = createTokenComponent<IconProps>();
interface ButtonProps { disabled: boolean;}
const Button:ParentComponent<ButtonProps> = (props) => { return ( <div> <button disabled={props.disabled}> {props.children} </button> </div> );};
export default Button;export default Object.assign(Button, { Icon });With this setup, you can now use the Button.Icon slot within the Button component. The Icon slot can accept any valid JSX or HTML content as its children, and you can also pass the before property to customize its behavior.
<Button> <Button.Icon before> <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> ... </svg> </Button.Icon></Button>Leveraging slot properties in components
Section titled “Leveraging slot properties in components”To utilize slot properties within a component, you can access them using the useToken function. This function retrieves the slot component, allowing you to work with its properties and children. The useToken function requires the slot component and the parent component’s children as arguments (in this case, the Button component’s children). Passing the parent component’s children ensures the slot and its properties are correctly identified.
In the example below, the before property of the Icon slot determines whether the icon is rendered before or after the button text.
import { createTokenComponent } from '@components/utils/tokenComponents';import { createTokenComponent, useToken } from '@components/utils/tokenComponents';
interface IconProps { before?: boolean}
const Icon = createTokenComponent<IconProps>();
interface ButtonProps { disabled: boolean}
const Button:ParentComponent<ButtonProps> = (props) => { const IconToken = useToken(Icon, props.children);
return ( <div> <button disabled={props.disabled}> {IconToken?.().before && IconToken?.().children} {props.children} {!IconToken?.().before && IconToken?.().children} </button> </div> );};
export default Button;export default Object.assign(Button, { Icon });Nested slots and wrapping slots with components
Section titled “Nested slots and wrapping slots with components”Nested slots are supported but require careful handling to ensure proper reactivity and accessibility of slot properties. When nesting slots, you must pass the parent component’s children correctly to the child slot.
For example, to wrap the Icon slot with another component and nest the IconSVG slot in it, you can use the following structure:
import { ParentComponent } from "solid-js";import { createTokenComponent, useToken } from '@components/utils/tokenComponents';import { TokenComponentProps } from '@components/types/ComponentProps';
const Icon = createTokenComponent<{ before?: boolean }>();const IconSVG = createTokenComponent<{ src?: string }>();
const ButtonIconSVG: ParentComponent<TokenComponentProps> = (props) => { const IconSVGToken = useToken(IconSVG, props.parentChildren);
return ( <div style={{ 'background-image': IconSVGToken?.().src }} /> );};
const ButtonIcon: ParentComponent<TokenComponentProps> = (props) => { const IconToken = useToken(Icon, props.parentChildren);
return ( <> IconSVG: <ButtonIconSVG parentChildren={IconToken?.().children} /> </> );};
interface ButtonProps { disabled: boolean;}
const Button: ParentComponent<ButtonProps> = (props) => { const IconToken = useToken(Icon, props.children);
return ( <div> <button disabled={props.disabled}> <Show when={IconToken?.().before}> <ButtonIcon parentChildren={props.children} /> </Show> {props.children} <Show when={!IconToken?.().before}> <ButtonIcon parentChildren={props.children} /> </Show> </button> </div> );};
export default Object.assign(Button, { Icon, IconSVG });Here, the TokenComponentProps type ensures that the parentChildren prop is passed to the ButtonIcon and ButtonIconSVG components. This prop allows the useToken function to correctly identify the slot and its properties.
With this setup, you can use the Button component with nested Icon and IconSVG slots. The Icon slot renders the icon before or after the button text, while the IconSVG slot handles the SVG icon. This approach also supports nesting the IconSVG slot inside the Icon slot, enabling more complex structures and better component organization.
<Button> <Button.Icon before> <Button.IconSVG src="path/to/icon.svg" /> </Button.Icon> Button text</Button>Conditional rendering of slots and their properties
Section titled “Conditional rendering of slots and their properties”Conditional rendering of a slot is supported. For instance, attempting to render a slot based on a condition:
const [renderIconBefore, setRenderIconBefore] = createSignal(false);<Button> {renderIconBefore() && <Button.Icon before/>} Text</Button>Or
const [renderIconBefore, setRenderIconBefore] = createSignal(false);<Button> <Show when={renderIconBefore()}> <Button.Icon before/> </Show> Text</Button>To conditionally modify a slot’s properties, you can also directly manipulate the slot’s properties in the component. For instance, to dynamically update the before property of the Icon slot based on a condition:
const [renderIconBefore, setRenderIconBefore] = createSignal(false);<Button> <Button.Icon before={renderIconBefore()} /> Text</Button>© 2026 Coherent Labs. All rights reserved.