Community Wolf
Community
APIAboutContact
Book a demo

Community Wolf

Real-time safety intelligence for citizens and the teams who protect them.

Community Tools

  • Public map
  • Namola
  • WhatsApp

Business Tools

  • Access Control
  • Intelligence
  • Safety API
  • Group Agents
  • Patrol Management
  • Roster Management
  • Safety Survey
  • Pricing
  • Pricing calculator

Resources

  • Docs
  • Changelog
  • Design system

Company

  • Community
  • Business
  • API
  • About
  • Contact

Get pilot updates

New features, city launches, and integration partnerships - delivered monthly.

Subscribe to updates

(c) 2026 Community Wolf. All rights reserved.

Privacy PolicyTerms of Service
Wolf design system
Foundations
  • Brand
  • Voice and tone
  • Colour
  • Typography
  • Spacing and layout
  • Radius, elevation and borders
  • Motion
  • Iconography
  • Imagery and photography
  • Data visualisation
  • Accessibility
Patterns
  • App shell
  • Hero sections
  • Empty states
  • Error states
  • Skeletons and loading
  • Forms
  • Tables and data density
  • Confirmation and destructive actions
  • Authentication surfaces
Components
  • Button
  • Input
  • Card
  • Badge
  • Dialog
  • Label
  • Textarea
  • Select
  • Checkbox
  • Radio group
  • Switch
  • Form field
  • Tabs
  • Popover
  • Tooltip
  • Accordion
  • Alert dialog
  • Confirm dialog
  • Toast (Sonner)
  • Skeleton
  • Empty state

components

Form field

Every Wolf form uses the same layout — label above control, helper below, error in destructive red. FormField standardises that shape and wires the a11y attributes for you.

Read the full spec

Sign-in form

Label, input and error message bound by context — no manual `htmlFor` or `aria-describedby` required. Try submitting with a bad email to see the error wiring.

We'll email you a magic sign-in link.

At least 8 characters.

tsx
const schema = z.object({
  email: z.string().email("Enter a valid email address"),
  password: z.string().min(8, "Use at least 8 characters"),
});

const form = useForm<z.infer<typeof schema>>({
  resolver: zodResolver(schema),
  defaultValues: { email: "", password: "" },
});

<Form {...form}>
  <form onSubmit={form.handleSubmit(onSubmit)}>
    <FormField
      control={form.control}
      name="email"
      render={({ field }) => (
        <FormItem>
          <FormLabel>Email</FormLabel>
          <FormControl>
            <Input type="email" {...field} />
          </FormControl>
          <FormDescription>We'll email you a magic link.</FormDescription>
          <FormMessage />
        </FormItem>
      )}
    />
    …
    <Button type="submit">Sign in</Button>
  </form>
</Form>
Previous — ComponentsSwitch
Next — ComponentsTabs