# Solid (http://yak.js.org/docs/solid)

> Use yak with Solid 2 and Vite through @yak/solid. Static styles compile to classes, and dynamic styles become CSS variables driven by signals.

`@yak/solid` brings the yak API to [Solid](https://www.solidjs.com). The SWC plugin extracts your CSS at build time,
as it does for React. The thin runtime that remains follows Solid's model, where components run once and dynamic
styles follow signals instead of re-renders.

> [!WARNING]
> `@yak/solid` is experimental and targets Solid 2, which is still a release candidate. Expect breaking changes while
> Solid 2 stabilizes. Solid 1 is not supported.

## Install dependencies [#install-dependencies]

Install `@yak/solid` together with the Solid 2 line of the Vite plugin (npm tag `next`):

```bash
npm i @yak/solid
npm i -D @solidjs/vite-plugin@next
```

`@yak/solid` needs `solid-js` and `@solidjs/web` 2.0.0-rc.15 or later, Vite 7 or later and Node.js 22.18 or later.

## Configure Vite [#configure-vite]

Add the `yak` plugin before `solid()`, so that it sees your original source:

```ts title="vite.config.ts"
import { defineConfig } from "vite";
import solid from "@solidjs/vite-plugin";
import { yak } from "@yak/solid/vite";

export default defineConfig({
  plugins: [yak(), solid()],
});
```

`yak()` takes the same options as the React Vite plugin, such as `minify`, `prefix`, `contextPath`, `basePath`,
`foldStatic` and `debug`. The [API reference](/docs/api#plugin-options) lists them all.

## Write styled components [#write-styled-components]

The API is the one you know from `@yak/react`. Interpolations that read props are tracked like any other reactive read
in Solid:

```tsx title="App.tsx"
import { styled, css } from "@yak/solid";
import { createSignal } from "solid-js";

const Button = styled.button<{ $primary?: boolean }>`
  color: #009688;
  ${(props) =>
    props.$primary &&
    css`
      border-width: 2px;
    `}
`;

const Progress = styled.div<{ $percent: number }>`
  height: 8px;
  background: #e5e5ef;

  &::before {
    content: "";
    display: block;
    height: 100%;
    width: ${(props) => props.$percent}%;
    background: #009688;
  }
`;

export function App() {
  const [percent, setPercent] = createSignal(30);
  return (
    <>
      <Progress $percent={percent()} />
      <Button $primary onClick={() => setPercent((p) => Math.min(p + 10, 100))}>
        More
      </Button>
    </>
  );
}
```

A styled component without interpolations compiles to a plain CSS class. Dynamic interpolations become CSS variables
on the element's inline `style`, all computed in one memo per element, so a prop change updates the `class` and
`style` bindings without re-creating the element.

The `css` prop works on every intrinsic element and maps to Solid's `class` attribute. Its types become available as
soon as you import `@yak/solid`:

```tsx
<p
  css={css`
    color: green;
  `}
/>
```

## Theming [#theming]

Create a `yak.context.ts` next to your `vite.config.ts`. The plugin picks it up automatically, and the module declaration
gives the theme its type:

```ts title="yak.context.ts"
export function getYakThemeContext() {
  return { highContrast: false };
}

declare module "@yak/solid" {
  export interface YakTheme extends ReturnType<typeof getYakThemeContext> {}
}
```

Wrap your app in `YakThemeProvider`. Its `theme` prop is reactive, so signal reads inside it stay live and a theme
change only updates the themed styles:

```tsx title="main.tsx"
import { render } from "@solidjs/web";
import { YakThemeProvider } from "@yak/solid";
import { createSignal } from "solid-js";
import { App } from "./App";

const [highContrast, setHighContrast] = createSignal(false);

render(
  () => (
    <YakThemeProvider theme={{ highContrast: highContrast() }}>
      <App />
    </YakThemeProvider>
  ),
  document.getElementById("root")!,
);
```

`useTheme()` returns an accessor, like a signal getter, and so does `props.theme` inside an interpolation:

```tsx
import { styled, useTheme } from "@yak/solid";

const Label = styled.span`
  color: ${(props) => (props.theme().highContrast ? "#000" : "#555")};
`;

function Toolbar() {
  const theme = useTheme();
  return <Label>{theme().highContrast ? "High contrast" : "Default"}</Label>;
}
```

## SolidStart [#solidstart]

The Solid 2 Vite plugin has SolidStart built in. Turn it on with the `start` option, and yak works with it like with any
other Solid app:

```ts title="vite.config.ts"
import { defineConfig } from "vite";
import solid from "@solidjs/vite-plugin";
import { yak } from "@yak/solid/vite";

export default defineConfig({
  plugins: [yak(), solid({ start: true })],
});
```

## Differences to @yak/react [#differences-to-yakreact]

If you come from `@yak/react`, the API stays the same apart from a few Solid-shaped details:

- `useTheme()` and `props.theme` return accessors, so you read `theme().highContrast` instead of `theme.highContrast`.
- Use `class` instead of `className`, also inside `.attrs({ ... })`.
- Components run once, and Solid's reactivity updates the styles instead of a re-render.

## Example project [#example-project]

[examples/vite-solid](https://github.com/galaxuslabs/yak/tree/main/examples/vite-solid) shows a full setup
with theming, keyframes, `.attrs()` and the `css` prop.

## Next steps [#next-steps]

- [Features](/docs/features): the shared API, shown with React
- [API reference](/docs/api#plugin-options): all plugin options
- [Troubleshooting](/docs/troubleshooting): build errors and missing styles
