Skip to content

Customization

Since you own the component code, you can customize anything. Here are common customization patterns.

Styling

Modify Classes

Add or change Tailwind classes:

Custom Stylestypescript
// In your copied component, modify the classes:

// Before

  Customer Name
  
    field} />
  


// After - with custom styling
"bg-gray-50 p-4 rounded-lg border">
  "font-semibold text-blue-600 text-sm uppercase">
    Customer Name
  
  
    field}
      className="border-blue-200 focus:border-blue-500"
    />
  

Theme Integration

Components use CSS variables. Update your global styles:

:root {
--primary: 234 89% 74%;
--primary-foreground: 0 0% 100%;
--radius: 0.5rem;
}

Adding Fields

Extend Form Schema

Extend Schematypescript
import { zod } from "@spaceinvoices/js-sdk";
import { z } from "zod";

// Extend the existing schema with custom fields
const extendedCustomerSchema = zod.customers.CreateCustomerBody.extend({
  // Add your custom fields
  internalReference: z.string().optional(),
  salesRepId: z.string().optional(),
  creditLimit: z.number().min(0).optional(),
});

type ExtendedCustomer = z.infer;

Add Form Field

Add Form Fieldtypescript
// In your copied CustomerForm component, add the new field:

control}
  name="internalReference"
  render={({ field }) => (
    
      Internal Reference
      
        Your internal tracking number for this customer
      
      
        "REF-001" {...field} />
      
      
    
  )}
/>

control}
  name="creditLimit"
  render={({ field }) => (
    <_FormItem>
      <_FormLabel>Credit Limit
      <_FormControl>
        <_Input
          _type="number"
          _placeholder="5000"
          {...field}
          onChange={(_e) => field.onChange(Number(e.target.value))}
        />
      
      <_FormMessage />
    
  )}
/>

Modifying Behavior

Change Validation

Custom Validationtypescript
import { z } from "zod";

// Add custom validation rules
const _invoiceSchema = z
  .object({
    date: z.string().min(1, "Date is required"),
    dueDate: z.string().min(1, "Due date is required"),
    items: z
      .array(
        z.object({
          name: z.string().min(1, "Item name required"),
          quantity: z.number().min(1, "Quantity must be at least 1"),
          price: z.number().min(0.01, "Price must be positive"),
        }),
      )
      .min(1, "At least one item required"),
    // Custom validation: due date must be after date
  })
  .refine((data) => new Date(data.dueDate) >= new Date(data.date), {
    message: "Due date must be on or after invoice date",
    path: ["dueDate"],
  });

Add Side Effects

Add Side Effectstypescript
// In your copied component, modify the mutation:

const _createInvoice = useMutation({
  mutationFn: (data) => sdk.invoices.create({ entityId, body: data }),
  onSuccess: (invoice) => {
    // Invalidate cache
    queryClient.invalidateQueries(["invoices", entityId]);

    // Custom side effects
    trackEvent("invoice_created", { id: invoice.id });
    sendWebhook("invoice.created", invoice);

    // Show notification
    toast.success(`Invoice ${invoice.number} created`);

    // Navigate
    onSuccess?.(invoice);
  },
  onError: (error) => {
    // Custom error handling
    logError("invoice_creation_failed", error);
    toast.error("Failed to create invoice");
  },
});

Translations

Add Language Support

Add Translationstypescript
// Create a translation file for your language
// components/space-invoices/customers/locales/fr.ts

export default {
  "customer.name": "Nom du client",
  "customer.email": "Adresse e-mail",
  "customer.address": "Adresse",
  "customer.city": "Ville",
  "customer.country": "Pays",
  "customer.taxNumber": "Numéro de TVA",
  "button.save": "Enregistrer",
  "button.cancel": "Annuler",
  "error.required": "Ce champ est obligatoire",
};


{t("customer.name")}

Using Different UI Library

If you’re not using shadcn/ui, update the imports:

// Before (shadcn/ui)
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
// After (your UI library)
import { Button } from "@chakra-ui/react";
import { Input } from "@chakra-ui/react";

Best Practices

  1. Keep a reference copy — Store the original components for comparison
  2. Document changes — Comment what you modified and why
  3. Test after updates — When pulling updates, test your customizations
  4. Use composition — Wrap components instead of modifying when possible

Next Steps