Babelize Elements
Getting Started

Contribution & Open Source

How to contribute a component to Babelize Elements — from opening an issue to shipping a pull request.

Contributing

Babelize Elements is an open-source, community-driven library. The components you see here were built by contributors — and the next one could be yours.

How it works

  1. Pick an issue — browse the GitHub issues for a component request marked good first issue or help wanted.
  2. Build the component — implement it in src/registry/components/ following the component template below.
  3. Open a pull request — our maintainers review it, request changes if needed, and merge it.
  4. It ships — merged components are documented on this site and available to every Babelize Elements user.

No component exists yet? Open an issue proposing one. Great candidates: language switchers, locale pickers, translation widgets, RTL utilities, pluralization helpers, and locale-aware formatters.

Component template

"use client";

import * as React from "react";
import { cn } from "@/lib/utils";
import { useControllableState } from "@/lib/use-controllable-state";
import type { Locale } from "./types";

export interface LanguageSelectProps extends Omit<
  React.ComponentPropsWithoutRef<"select">,
  "value" | "defaultValue" | "onChange"
> {
  /** Available locales — only `code` is required */
  locales: Locale[];
  /** Selected locale code. Provide this to control the component. */
  value?: string;
  /** Initial locale code when uncontrolled */
  defaultValue?: string;
  /** Fired once per selection */
  onValueChange?: (code: string) => void;
}

export const LanguageSelect = React.forwardRef<HTMLSelectElement, LanguageSelectProps>(
  function LanguageSelect(
    { locales, value, defaultValue, onValueChange, className, ...rest },
    ref,
  ) {
    const [locale, setLocale] = useControllableState(
      value,
      defaultValue ?? locales[0]?.code ?? "",
      onValueChange,
    );

    return (
      <select
        ref={ref}
        value={locale}
        onChange={(e) => setLocale(e.target.value)}
        className={cn(
          "h-10 rounded-md border border-zinc-200 bg-white px-3 text-sm outline-none transition-colors focus:border-emerald-500 dark:border-zinc-800 dark:bg-zinc-900",
          className,
        )}
        {...rest}
      >
        {locales.map((l) => (
          <option key={l.code} value={l.code}>
            {l.label ?? l.code}
          </option>
        ))}
      </select>
    );
  },
);

Note the four conventions every component follows: a value / defaultValue / onValueChange trio via useControllableState, a forwarded ref, ...rest spread onto the root element, and the shared Locale type from ./types rather than a local copy.

Contribution checklist

  • TypeScript-first with exported interfaces for all props
  • Localization-aware: handles locale codes, pluralization, or RTL as applicable
  • Accessible: keyboard support, ARIA labels, focus states
  • Styled with Tailwind CSS
  • A short demo or usage example for the docs

Need help?

Open a discussion on GitHub or join the Babelize community. We're friendly.

On this page