diff --git a/README.md b/README.md
index c2aee406..ea1650cf 100644
--- a/README.md
+++ b/README.md
@@ -95,6 +95,7 @@ resistorProps.parse({ resistance: "10k" } as ResistorPropsInput);
| `` | [`SchematicRowProps`](#schematicrowprops-schematicrow) |
| `` | [`SchematicSectionProps`](#schematicsectionprops-schematicsection) |
| `` | [`SchematicSheetProps`](#schematicsheetprops-schematicsheet) |
+| `` | [`SchematicSymbolProps`](#schematicsymbolprops-schematicsymbol) |
| `` | [`SchematicTableProps`](#schematictableprops-schematictable) |
| `` | [`SchematicTextProps`](#schematictextprops-schematictext) |
| `` | [`SilkscreenCircleProps`](#silkscreencircleprops-silkscreencircle) |
@@ -1691,6 +1692,30 @@ export interface SchematicSheetProps {
[Source](https://github.com/tscircuit/props/blob/main/lib/components/schematic-sheet.ts)
+### SchematicSymbolProps ``
+
+```ts
+export interface SchematicSymbolProps {
+ /** Stable name for this representation, such as `A` or `B`. */
+ name: string;
+ /** Optional human-facing name shown in the schematic. */
+ displayName?: string;
+ /** Selector for the physical component represented by this symbol. */
+ chipRef?: string;
+ /** Name of the symbol from the schematic-symbol library. */
+ symbolName: string;
+ /** Maps symbol port labels to physical component port selectors. */
+ connections?: Connections;
+ schX?: Distance;
+ schY?: Distance;
+ schRotation?: number | string;
+ schSectionName?: string;
+ schSheetName?: string;
+}
+```
+
+[Source](https://github.com/tscircuit/props/blob/main/lib/components/schematic-symbol.ts)
+
### SchematicTableProps ``
```ts
diff --git a/generated/COMPONENT_TYPES.md b/generated/COMPONENT_TYPES.md
index 39b5cdcc..3a76247c 100644
--- a/generated/COMPONENT_TYPES.md
+++ b/generated/COMPONENT_TYPES.md
@@ -3719,6 +3719,45 @@ export const schematicSheetProps = z.object({
})
```
+### schematic-symbol
+
+```typescript
+/**
+ * Places a named schematic-symbol representation of an existing physical
+ * component. The connection keys are labels exposed by `symbolName`; each
+ * value selects the corresponding port on the component referenced by
+ * `chipRef`.
+ *
+ * This is a schematic-only projection, so it accepts only the identity,
+ * connection, and schematic placement props it needs.
+ */
+export interface SchematicSymbolProps {
+ name: string
+ displayName?: string
+ chipRef?: string
+ symbolName: string
+ connections?: Connections
+ schX?: Distance
+ schY?: Distance
+ schRotation?: number | string
+ schSectionName?: string
+ schSheetName?: string
+}
+/** Maps symbol port labels to physical component port selectors. */
+export const schematicSymbolProps = z.object({
+ name: z.string().min(1),
+ displayName: z.string().optional(),
+ chipRef: z.string().min(1).optional(),
+ symbolName: z.string().min(1),
+ connections: schematicSymbolConnections.optional(),
+ schX: distance.optional(),
+ schY: distance.optional(),
+ schRotation: rotation.optional(),
+ schSectionName: z.string().optional(),
+ schSheetName: z.string().optional(),
+})
+```
+
### schematic-table
```typescript
diff --git a/generated/PROPS_OVERVIEW.md b/generated/PROPS_OVERVIEW.md
index 6dd36661..c6229d94 100644
--- a/generated/PROPS_OVERVIEW.md
+++ b/generated/PROPS_OVERVIEW.md
@@ -2101,6 +2101,25 @@ export interface SchematicSheetProps {
}
+export interface SchematicSymbolProps {
+ /** Stable name for this representation, such as `A` or `B`. */
+ name: string
+ /** Optional human-facing name shown in the schematic. */
+ displayName?: string
+ /** Selector for the physical component represented by this symbol. */
+ chipRef?: string
+ /** Name of the symbol from the schematic-symbol library. */
+ symbolName: string
+ /** Maps symbol port labels to physical component port selectors. */
+ connections?: Connections
+ schX?: Distance
+ schY?: Distance
+ schRotation?: number | string
+ schSectionName?: string
+ schSheetName?: string
+}
+
+
export interface SchematicTableProps {
schX?: number | string
schY?: number | string
diff --git a/lib/components/schematic-symbol.ts b/lib/components/schematic-symbol.ts
new file mode 100644
index 00000000..d097d5f7
--- /dev/null
+++ b/lib/components/schematic-symbol.ts
@@ -0,0 +1,59 @@
+import { rotation } from "circuit-json"
+import { connectionTarget } from "lib/common/connectionsProp"
+import { distance, type Distance } from "lib/common/distance"
+import { expectTypesMatch } from "lib/typecheck"
+import type { Connections } from "lib/utility-types/connections-and-selectors"
+import { z } from "zod"
+
+/**
+ * Places a named schematic-symbol representation of an existing physical
+ * component. The connection keys are labels exposed by `symbolName`; each
+ * value selects the corresponding port on the component referenced by
+ * `chipRef`.
+ *
+ * This is a schematic-only projection, so it accepts only the identity,
+ * connection, and schematic placement props it needs.
+ */
+export interface SchematicSymbolProps {
+ /** Stable name for this representation, such as `A` or `B`. */
+ name: string
+ /** Optional human-facing name shown in the schematic. */
+ displayName?: string
+ /** Selector for the physical component represented by this symbol. */
+ chipRef?: string
+ /** Name of the symbol from the schematic-symbol library. */
+ symbolName: string
+ /** Maps symbol port labels to physical component port selectors. */
+ connections?: Connections
+ schX?: Distance
+ schY?: Distance
+ schRotation?: number | string
+ schSectionName?: string
+ schSheetName?: string
+}
+
+const schematicSymbolConnections = z
+ .custom()
+ .pipe(z.record(z.string(), connectionTarget))
+ .refine((value) => Object.keys(value).length > 0, {
+ message: "connections must map at least one schematic symbol port",
+ })
+
+export const schematicSymbolProps = z.object({
+ name: z.string().min(1),
+ displayName: z.string().optional(),
+ chipRef: z.string().min(1).optional(),
+ symbolName: z.string().min(1),
+ connections: schematicSymbolConnections.optional(),
+ schX: distance.optional(),
+ schY: distance.optional(),
+ schRotation: rotation.optional(),
+ schSectionName: z.string().optional(),
+ schSheetName: z.string().optional(),
+})
+
+export type InferredSchematicSymbolProps = z.input
+
+expectTypesMatch>(
+ true,
+)
diff --git a/lib/index.ts b/lib/index.ts
index 421456d5..f6584961 100644
--- a/lib/index.ts
+++ b/lib/index.ts
@@ -104,6 +104,7 @@ export * from "./components/ammeter"
export * from "./components/schematic-arc"
export * from "./components/toolingrail"
export * from "./components/schematic-box"
+export * from "./components/schematic-symbol"
export * from "./components/schematic-circle"
export * from "./components/schematic-rect"
export * from "./components/schematic-line"
diff --git a/tests/schematic-symbol.test.ts b/tests/schematic-symbol.test.ts
new file mode 100644
index 00000000..fea8694e
--- /dev/null
+++ b/tests/schematic-symbol.test.ts
@@ -0,0 +1,59 @@
+import { expect, test } from "bun:test"
+import { schematicSymbolProps } from "lib/components/schematic-symbol"
+
+test("schematic symbol parses a physical component projection", () => {
+ const parsed = schematicSymbolProps.parse({
+ name: "A",
+ displayName: "Q1A",
+ chipRef: ".Q1",
+ symbolName: "n_channel_e_mosfet_transistor",
+ connections: {
+ gate: ".Q1 > .G1",
+ source: ".Q1 > .S1",
+ drain: [".Q1 > .pin7", ".Q1 > .pin8"],
+ },
+ schX: "2mm",
+ schY: "-1mm",
+ schRotation: "90deg",
+ schSectionName: "Switching",
+ schSheetName: "Power",
+ })
+
+ expect(parsed).toEqual({
+ name: "A",
+ displayName: "Q1A",
+ chipRef: ".Q1",
+ symbolName: "n_channel_e_mosfet_transistor",
+ connections: {
+ gate: ".Q1 > .G1",
+ source: ".Q1 > .S1",
+ drain: [".Q1 > .pin7", ".Q1 > .pin8"],
+ },
+ schX: 2,
+ schY: -1,
+ schRotation: 90,
+ schSectionName: "Switching",
+ schSheetName: "Power",
+ })
+})
+
+test("schematic symbol allows optional chipRef and connections", () => {
+ const parsed = schematicSymbolProps.parse({
+ name: "B",
+ symbolName: "n_channel_e_mosfet_transistor",
+ })
+
+ expect(parsed.chipRef).toBeUndefined()
+ expect(parsed.connections).toBeUndefined()
+})
+
+test("schematic symbol rejects an empty connections map", () => {
+ expect(
+ schematicSymbolProps.safeParse({
+ name: "A",
+ chipRef: ".Q1",
+ symbolName: "n_channel_e_mosfet_transistor",
+ connections: {},
+ }).success,
+ ).toBe(false)
+})