shadcn-solid Documentation

repository·main·Indexed 20 days ago

https://github.com/hngngn/shadcn-solid

A community-driven port of the shadcn/ui component library for the SolidJS framework. It provides accessible and highly customizable UI components, such as Accordion, Alert Dialog, Badge, and Breadcrumbs, designed to be copied and pasted directly into projects to serve as a foundation for custom component libraries.

Tokens
51.7K
Snippets
150
Records
215
Agent score
72%

What's inside shadcn-solid

  1. Overview of shadcn-solid

    main
    shadcn-solid is an unofficial, community-led port of shadcn/ui specifically for SolidJS. It provides accessible and highly customizable components designed to be copied and pasted directly into your applications. The project is intended to serve as a foundation for developers to build their own custom component libraries.
  2. Understand the shadcn-solid philosophy

    main

    shadcn-solid is not a traditional NPM component library. Instead, it is a system for building your own component library. Unlike standard libraries where you import pre-compiled components, shadcn-solid provides the actual source code for components, allowing for full transparency and direct modification.

    Key principles include:

    • Open Code: You own the component code and can edit it directly to fit your design system.
    • Composition: Components use a common, composable interface for predictability.
    • Distribution: Uses a flat-file schema and a CLI to distribute components.
    • Beautiful Defaults: Provides consistent, high-quality default styles that are easy to override.
  3. How shadcn-solid distributes components

    main

    shadcn-solid functions as a code distribution system using two main pillars:

    1. Schema: A flat-file structure that defines components, their required dependencies, and their properties.
    2. CLI: A command-line tool used to install and distribute components across projects. This tool is designed with cross-framework support in mind.

    The schema can be used to distribute your own custom components to other projects or as a reference for AI tools to generate new components that match your existing design system.

  4. Badge variants: Secondary, Destructive, and Outline

    main

    The Badge component supports different visual styles via variants:

    • Secondary: A subtle style for less prominent information.
    • Destructive: A high-contrast style (usually red) used for error states or critical information.
    • Outline: A transparent style with a border for a clean, outlined look.
    // Example of using different variants
    <Badge variant="secondary">Secondary</Badge>
    <Badge variant="destructive">Destructive</Badge>
    <Badge variant="outline">Outline</Badge>
  5. The background and foreground color convention

    main

    shadcn-solid follows a background and foreground convention for color pairs.

    • The base variable (e.g., --primary) is used for the background color of the component.
    • The -foreground suffix (e.g., --primary-foreground) is used for the text/content color that sits on top of that background.

    When using utility classes, the background suffix is omitted for the background color itself.

    Example: If you have --primary and --primary-foreground defined, use them like this:

    <div class="bg-primary text-primary-foreground">Hello</div>
    <div class="bg-primary text-primary-foreground">Hello</div>
  6. How Chart components and Unovis work together

    main

    The Chart components are built using composition. ChartContainer acts as the provider for data and configuration, while you use Unovis components (like VisArea, VisBar, etc.) to define the actual chart type. You can also inject custom UI components like ChartTooltipContent or ChartCrosshair into the Unovis lifecycle to enhance the user experience.

    import { VisArea, VisTooltip } from "@unovis/solid"
    import {
      ChartContainer,
      ChartCrosshair,
      ChartTooltipContent,
    } from "@/components/ui/charts"
    
    const MyChart = () => {
      return (
        <ChartContainer data={data} type="xy" config={chartConfig}>
          <VisArea ... />
          <ChartCrosshair
            template={(props) => (
              <ChartTooltipContent labelKey="month" indicator="line" {...props} />
            )}
          />
          <VisTooltip ... />
        </ChartContainer>
      )
    }
  7. How Open Code and Headless Architecture work in shadcn-solid

    main

    shadcn-solid uses a headless component architecture. This means the core logic and functionality are handled by underlying dependencies like kobalte-ui or corvu-ui.

    Because the topmost layer (the code you actually see and edit in your project) is decoupled from the implementation details of these libraries, you can receive bug fixes and updates by updating your dependencies without losing your custom design system modifications. You modify the component code directly rather than wrapping components or fighting style overrides.

  8. How the Sidebar components work together

    main

    The Sidebar is a highly composable system. To build a functional sidebar, you should use the following structure:

    • SidebarProvider: The root wrapper that manages the collapsible state and provides context to all other components. Always wrap your application or the sidebar area in this.
    • Sidebar: The main container for the sidebar content.
    • SidebarHeader / SidebarFooter: Sticky sections at the top and bottom of the sidebar.
    • SidebarContent: The main scrollable area of the sidebar.
    • SidebarGroup: A logical section within the SidebarContent (often used to group menu items).
    • SidebarTrigger: A component used to toggle the sidebar's open/closed state.

    This composition allows you to easily integrate other shadcn/ui components like DropdownMenu or Collapsible within the sidebar structure.

    // Basic structural example
    <Sidebar>
      <SidebarHeader />
      <SidebarContent>
        <SidebarGroup />
      </SidebarContent>
      <SidebarFooter />
    </Sidebar>
  9. Theming approaches in shadcn-solid

    main

    You can theme your application using two primary methods:

    1. CSS Variables (Recommended): Use semantic variables that automatically adapt to light and dark modes. This is the preferred way to ensure consistency across components.

      • Example: <div class="bg-background text-foreground" />
    2. Utility Classes: Use standard Tailwind CSS utility classes for specific colors or manual dark mode overrides.

      • Example: <div class="bg-zinc-950 dark:bg-white" />
    <div class="bg-background text-foreground" />
  10. Integrate TanStack Form fields with shadcn-solid components

    main

    When using form.Field, you receive a field() function via a render prop. Use this function to bind the component's state and handlers to TanStack Form:

    • Value: field().state.value
    • Change Handler: field().handleChange
    • Blur Handler: field().handleBlur
    • Name: field().name
    • Errors: field().state.meta.errors
    • Validation State: To visually indicate errors, calculate validationState based on whether the field has been touched and is invalid: validationState={field().state.meta.isTouched && !field().state.meta.isValid ? "invalid" : "valid"}
    <form.Field name="title">
      {(field) => (
        <TextField
          validationState={
            field().state.meta.isTouched && !field().state.meta.isValid
              ? "invalid"
              : "valid"
          }
          name={field().name}
          value={field().state.value}
          onBlur={field().handleBlur}
          onChange={field().handleChange}
        >
          <TextFieldLabel>Bug Title</TextFieldLabel>
          <TextFieldInput />
          <TextFieldErrorMessage errors={field().state.meta.errors} />
        </TextField>
      )}
    </form.Field>
  11. Use the Select component

    main

    The Select component is composed of several sub-components. You provide an array of options and an itemComponent to define how individual items are rendered. The SelectTrigger holds the SelectValue, which can use a function to display the currently selected option's value. SelectPortal and SelectContent are used to render the dropdown menu.

    import {
      Select,
      SelectContent,
      SelectItem,
      SelectPortal,
      SelectTrigger,
      SelectValue,
    } from "@components/ui/select"
    
    // ...
    
    <Select
      options={optionsArray}
      itemComponent={(props) => (
        <SelectItem item={props.item}>{props.item.rawValue}</SelectItem>
      )}
    >
      <SelectTrigger>
        <SelectValue<string>>{(state) => state.selectedOption()}</SelectValue>
      </SelectTrigger>
      <SelectPortal>
        <SelectContent />
      </SelectPortal>
    </Select>